readme update

This commit is contained in:
Steve Androulakis
2025-01-09 15:30:37 -08:00
parent 2f22af500f
commit 928788b0bb
5 changed files with 24 additions and 74 deletions

View File

@@ -2,17 +2,17 @@
Work in progress. Work in progress.
This demo shows a multi-turn conversation with an AI agent running inside a Temporal workflow. The goal is to collect information towards a goal. There's a simple DSL input for collecting information (currently set up to use mock functions to search for events, book flights around those events then create an invoice for those flights, see `send_message.py`). The AI will respond with clarifications and ask for any missing information to that goal. It uses a local LLM via Ollama. This demo shows a multi-turn conversation with an AI agent running inside a Temporal workflow. The goal is to collect information towards a goal. There's a simple DSL input for collecting information (currently set up to use mock functions to search for events, book flights around those events then create an invoice for those flights). The AI will respond with clarifications and ask for any missing information to that goal. It uses a local LLM via Ollama.
## Setup ## Setup
* See .env_example for the required environment variables.
* Requires an OpenAI key for the gpt-4o model. Set this in the `OPENAI_API_KEY` environment variable in .env * Requires an OpenAI key for the gpt-4o model. Set this in the `OPENAI_API_KEY` environment variable in .env
* Requires a rapidapi key for sky-scrapper (how we find flights). Set this in the `RAPIDAPI_KEY` environment variable in .env * Requires a Rapidapi key for sky-scrapper (how we find flights). Set this in the `RAPIDAPI_KEY` environment variable in .env
* It's free to sign up and get a key at [RapidAPI](https://rapidapi.com/apiheya/api/sky-scrapper) * It's free to sign up and get a key at [RapidAPI](https://rapidapi.com/apiheya/api/sky-scrapper)
* If you're lazy go to `tools/search_flights.py` and replace the `get_flights` function with the mock `search_flights_example` that exists in the same file. * If you're lazy go to `tools/search_flights.py` and replace the `get_flights` function with the mock `search_flights_example` that exists in the same file.
* Requires a Stripe key for the `create_invoice` tool. Set this in the `STRIPE_API_KEY` environment variable in .env * Requires a Stripe key for the `create_invoice` tool. Set this in the `STRIPE_API_KEY` environment variable in .env
* It's free to sign up and get a key at [Stripe](https://stripe.com/) * It's free to sign up and get a key at [Stripe](https://stripe.com/)
* If you're lazy go to `tools/create_invoice.py` and replace the `create_invoice` function with the mock `create_invoice_example` that exists in the same file. * If you're lazy go to `tools/create_invoice.py` and replace the `create_invoice` function with the mock `create_invoice_example` that exists in the same file.
* See .env_example for the required environment variables.
* Install and run Temporal. Follow the instructions in the [Temporal documentation](https://learn.temporal.io/getting_started/python/dev_environment/#set-up-a-local-temporal-service-for-development-with-temporal-cli) to install and run the Temporal server. * Install and run Temporal. Follow the instructions in the [Temporal documentation](https://learn.temporal.io/getting_started/python/dev_environment/#set-up-a-local-temporal-service-for-development-with-temporal-cli) to install and run the Temporal server.
* Install the dependencies: `poetry install` * Install the dependencies: `poetry install`
@@ -22,31 +22,21 @@ Deprecated:
## Running the example ## Running the example
### Temporal ### Run a Temporal Dev Server
From the /scripts directory: On a Mac
```bash
brew install temporal
temporal server start-dev
```
1. Run the worker: `poetry run python run_worker.py` ### Run a Temporal Worker
2. In another terminal run the client with a prompt.
Example: `poetry run python send_message.py 'Can you find events in march in oceania?'` From the `/scripts` directory:
3. View the worker's output for the response. - Run the worker: `poetry run python run_worker.py`
4. Give followup prompts by signaling the workflow.
Example: `poetry run python send_message.py 'I want to fly from San Francisco'` Then run the API and UI using the instructions below.
NOTE: The workflow will pause on the 'confirm' step until the user sends a 'confirm' signal. Use `poetry run python get_tool_data.py` query to see the current state of the workflow.
You can send a 'confirm' signal using `poetry run python send_confirm.py`
5. Get the conversation history summary by querying the workflow.
Example: `poetry run python get_history.py`
6. To end the chat session, run `poetry run python end_chat.py`
The chat session will end if it has collected enough information to complete the task or if the user explicitly ends the chat session.
Run query get_tool_data to see the data the tool has collected so far.
### API ### API
- `poetry run uvicorn api.main:app --reload` to start the API server. - `poetry run uvicorn api.main:app --reload` to start the API server.
@@ -56,9 +46,11 @@ Run query get_tool_data to see the data the tool has collected so far.
- `cd frontend` - `cd frontend`
- `npm install` to install the dependencies. - `npm install` to install the dependencies.
- `npm run dev` to start the dev server. - `npm run dev` to start the dev server.
- Access the UI at `http://localhost:5173`
## Customizing the agent ## Customizing the agent
- `tool_registry.py` contains the mapping of tool names to tool definitions (so the AI understands how to use them) - `tool_registry.py` contains the mapping of tool names to tool definitions (so the AI understands how to use them)
- `goal_registry.py` contains descriptions of goals and the tools used to achieve them
- The tools themselves are defined in their own files in `/tools` - The tools themselves are defined in their own files in `/tools`
- Note the mapping in `tools/__init__.py` to each tool - Note the mapping in `tools/__init__.py` to each tool
- See main.py where some tool-specific logic is defined (todo, move this to the tool definition) - See main.py where some tool-specific logic is defined (todo, move this to the tool definition)

View File

@@ -34,7 +34,6 @@ async def main():
if __name__ == "__main__": if __name__ == "__main__":
print("Starting worker") print("Starting worker")
print("Then run 'python send_message.py \"<prompt>\"'")
logging.basicConfig(level=logging.INFO) logging.basicConfig(level=logging.INFO)

View File

@@ -1,42 +0,0 @@
import asyncio
import sys
from temporalio.client import Client
from models.data_types import CombinedInput, AgentGoal, ToolWorkflowParams
from tools.tool_registry import event_travel_tools
from workflows.tool_workflow import ToolWorkflow
async def main(prompt: str):
# Build the AgentGoal
agent_goal = AgentGoal(
tools=event_travel_tools,
description="Helps the user find an event to travel to, search flights, and create an invoice for those flights.",
)
# 2) Create combined input
combined_input = CombinedInput(
tool_params=ToolWorkflowParams(None, None),
agent_goal=agent_goal,
)
# 3) Connect to Temporal and start or signal the workflow
client = await Client.connect("localhost:7233")
workflow_id = "agent-workflow"
await client.start_workflow(
ToolWorkflow.run,
combined_input,
id=workflow_id,
task_queue="agent-task-queue",
start_signal="user_prompt",
start_signal_args=[prompt],
)
if __name__ == "__main__":
if len(sys.argv) != 2:
print("Usage: python send_message.py '<prompt>'")
print("Example: python send_message.py 'I want an event in Oceania this March'")
else:
asyncio.run(main(sys.argv[1]))

View File

@@ -14,16 +14,16 @@ goal_event_flight_invoice = AgentGoal(
example_conversation_history="\n ".join( example_conversation_history="\n ".join(
[ [
"user: I'd like to travel to an event", "user: I'd like to travel to an event",
"agent: Sure! Let's start by finding an event you'd like to attend. Could you tell me which city and month you're interested in?", "agent: Sure! Let's start by finding an event you'd like to attend. I know about events in Australia and New Zealand cities. Could you tell me which city and month you're interested in?",
"user: In Sao Paulo, Brazil, in February", "user: sydney in may please",
"agent: Great! Let's find an events in Sao Paulo, Brazil in February.", "agent: Great! Let's find an events in Sydney in May.",
"user_confirmed_tool_run: <user clicks confirm on FindEvents tool>", "user_confirmed_tool_run: <user clicks confirm on FindEvents tool>",
"tool_result: { 'event_name': 'Carnival', 'event_date': '2023-02-25' }", "tool_result: { 'event_name': 'Vivid Sydney', 'event_date': '2023-05-01' }",
"agent: Found an event! There's Carnival on 2023-02-25, ending on 2023-02-28. Would you like to search for flights around these dates?", "agent: Found an event! There's Vivid Sydney on May 1 2025, ending on May 14 2025. Would you like to search for flights around these dates?",
"user: Yes, please", "user: Yes, please",
"agent: Let's search for flights around these dates. Could you provide your departure city?", "agent: Let's search for flights around these dates. Could you provide your departure city?",
"user: New York", "user: San Francisco",
"agent: Thanks, searching for flights from New York to Sao Paulo around 2023-02-25 to 2023-02-28.", "agent: Thanks, searching for flights from San Francisco to Sydney around 2023-02-25 to 2023-02-28.",
"user_confirmed_tool_run: <user clicks confirm on SearchFlights tool>" "user_confirmed_tool_run: <user clicks confirm on SearchFlights tool>"
'tool_result: results including {"flight_number": "CX101", "return_flight_number": "CX102", "price": 850.0}', 'tool_result: results including {"flight_number": "CX101", "return_flight_number": "CX102", "price": 850.0}',
"agent: Found some flights! The cheapest is CX101 for $850. Would you like to generate an invoice for this flight?", "agent: Found some flights! The cheapest is CX101 for $850. Would you like to generate an invoice for this flight?",

View File

@@ -2,7 +2,8 @@ from models.tool_definitions import ToolDefinition, ToolArgument
find_events_tool = ToolDefinition( find_events_tool = ToolDefinition(
name="FindEvents", name="FindEvents",
description="Find upcoming events to travel to given a location or city (e.g., 'Oceania') and a date or month", description="Find upcoming events to travel to a given city (e.g., 'Melbourne') and a date or month. "
"It knows about events in Oceania only (e.g. major Australian and New Zealand cities).",
arguments=[ arguments=[
ToolArgument( ToolArgument(
name="city", name="city",