mirror of
https://github.com/temporal-community/temporal-ai-agent.git
synced 2026-03-15 14:08:08 +01:00
vastly improved prompt history
This commit is contained in:
@@ -31,6 +31,8 @@ class ToolActivities:
|
|||||||
|
|
||||||
response: ChatResponse = chat(model=model_name, messages=messages)
|
response: ChatResponse = chat(model=model_name, messages=messages)
|
||||||
|
|
||||||
|
print(f"Chat response: {response.message.content}")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
data = json.loads(response.message.content)
|
data = json.loads(response.message.content)
|
||||||
except json.JSONDecodeError as e:
|
except json.JSONDecodeError as e:
|
||||||
|
|||||||
@@ -7,62 +7,47 @@ def generate_genai_prompt(
|
|||||||
tools_data: ToolsData, conversation_history: str, raw_json: Optional[str] = None
|
tools_data: ToolsData, conversation_history: str, raw_json: Optional[str] = None
|
||||||
) -> str:
|
) -> str:
|
||||||
"""
|
"""
|
||||||
Generates json containing a unified prompt for an AI system to:
|
Generates a concise prompt for producing or validating JSON instructions.
|
||||||
- Understand the conversation so far.
|
|
||||||
- Know which tools exist and their arguments.
|
|
||||||
- Produce or validate JSON instructions accordingly.
|
|
||||||
|
|
||||||
:param tools_data: An object containing your tool definitions.
|
|
||||||
:param conversation_history: The user's conversation history.
|
|
||||||
:param raw_json: The existing JSON to validate/correct (if any).
|
|
||||||
:return: A json containing the merged instructions.
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
prompt_lines = []
|
prompt_lines = []
|
||||||
|
|
||||||
# Intro / Role
|
# Intro / Role
|
||||||
prompt_lines.append(
|
prompt_lines.append(
|
||||||
"You are an AI assistant that must produce or validate JSON instructions "
|
"You are an AI assistant that must produce or validate JSON instructions "
|
||||||
"for a set of tools in order to achieve the user's goals."
|
"to properly call a set of tools. Respond with valid JSON only."
|
||||||
)
|
)
|
||||||
prompt_lines.append("")
|
|
||||||
|
|
||||||
# Conversation History
|
# Conversation History
|
||||||
prompt_lines.append("=== Conversation History ===")
|
prompt_lines.append("=== Conversation History ===")
|
||||||
prompt_lines.append(
|
prompt_lines.append(
|
||||||
"Analyze this history for context on tool usage, known arguments, and what's left to do."
|
"Use this history to understand needed tools, arguments, and the user's goals:"
|
||||||
)
|
)
|
||||||
prompt_lines.append(conversation_history)
|
prompt_lines.append("BEGIN CONVERSATION HISTORY")
|
||||||
|
prompt_lines.append(json.dumps(conversation_history, indent=2))
|
||||||
|
prompt_lines.append("END CONVERSATION HISTORY")
|
||||||
prompt_lines.append("")
|
prompt_lines.append("")
|
||||||
|
|
||||||
# Tools Definitions
|
# Tools Definitions
|
||||||
prompt_lines.append("=== Tools Definitions ===")
|
prompt_lines.append("=== Tools Definitions ===")
|
||||||
|
prompt_lines.append(f"There are {len(tools_data.tools)} available tools:")
|
||||||
|
prompt_lines.append(", ".join([t.name for t in tools_data.tools]))
|
||||||
|
prompt_lines.append("")
|
||||||
for tool in tools_data.tools:
|
for tool in tools_data.tools:
|
||||||
prompt_lines.append(f"Tool name: {tool.name}")
|
prompt_lines.append(f"Tool name: {tool.name}")
|
||||||
prompt_lines.append(f" Description: {tool.description}")
|
prompt_lines.append(f" Description: {tool.description}")
|
||||||
prompt_lines.append(" Required arguments:")
|
prompt_lines.append(" Required args:")
|
||||||
for arg in tool.arguments:
|
for arg in tool.arguments:
|
||||||
prompt_lines.append(f" - {arg.name} ({arg.type}): {arg.description}")
|
prompt_lines.append(f" - {arg.name} ({arg.type}): {arg.description}")
|
||||||
prompt_lines.append("")
|
prompt_lines.append("")
|
||||||
|
|
||||||
# Instructions for Generating JSON (Always Shown)
|
# Instructions for JSON Generation
|
||||||
prompt_lines.append("=== Instructions for JSON Generation ===")
|
prompt_lines.append("=== Instructions for JSON Generation ===")
|
||||||
prompt_lines.append(
|
prompt_lines.append(
|
||||||
"1. You may sequentially call multiple tools, each requiring specific arguments."
|
"Your JSON format must be:\n"
|
||||||
)
|
|
||||||
prompt_lines.append(
|
|
||||||
"2. If any required argument is missing, set 'next': 'question' and ask the user for it."
|
|
||||||
)
|
|
||||||
prompt_lines.append(
|
|
||||||
"3. Once all arguments for a tool are known, set 'next': 'confirm' with 'tool' set to that tool's name."
|
|
||||||
)
|
|
||||||
prompt_lines.append("4. If no further actions are required, set 'next': 'done'.")
|
|
||||||
prompt_lines.append(
|
|
||||||
"5. Always respond with valid JSON in this format:\n"
|
|
||||||
"{\n"
|
"{\n"
|
||||||
' "response": "<plain text>",\n'
|
' "response": "<plain text>",\n'
|
||||||
' "next": "<question|confirm|done>",\n'
|
' "next": "<question|confirm|done>",\n'
|
||||||
' "tool": "<tool_name or none>",\n'
|
' "tool": "<tool_name or null>",\n'
|
||||||
' "args": {\n'
|
' "args": {\n'
|
||||||
' "<arg1>": "<value1 or null>",\n'
|
' "<arg1>": "<value1 or null>",\n'
|
||||||
' "<arg2>": "<value2 or null>",\n'
|
' "<arg2>": "<value2 or null>",\n'
|
||||||
@@ -71,79 +56,75 @@ def generate_genai_prompt(
|
|||||||
"}"
|
"}"
|
||||||
)
|
)
|
||||||
prompt_lines.append(
|
prompt_lines.append(
|
||||||
"6. Use 'next': 'question' if you lack any required arguments based on the history and prompt. "
|
"1. You may call multiple tools sequentially. Each requires specific arguments.\n"
|
||||||
"Use 'next': 'confirm' only if NO arguments are missing. "
|
'2. If ANY required argument is missing, use "next": "question" and prompt the user.\n'
|
||||||
"Use 'next': 'done' and tool: 'null' if you have successfully completed all tools "
|
'3. If all required arguments are known, use "next": "confirm" and set "tool" to the tool name.\n'
|
||||||
"Don't offer any additional tools beyond the tools listed. "
|
'4. If no further actions are needed, use "next": "done" and "tool": "null".\n'
|
||||||
"DON'T editorialize or add extra information to a 'done' response. "
|
'5. Keep "response" short and user-friendly. Do not include any metadata or editorializing.\n'
|
||||||
"Example done response: {'response': 'All tools completed.', 'next': 'done', 'tool': 'null', 'args': {}} "
|
|
||||||
)
|
)
|
||||||
prompt_lines.append(
|
|
||||||
"7. Keep 'response' user-friendly with no extra commentary. Stick to valid JSON syntax. "
|
|
||||||
"Your goal is to guide the user through the running of these tools and elicit missing information."
|
|
||||||
)
|
|
||||||
prompt_lines.append("")
|
|
||||||
|
|
||||||
# Instructions for Validation (Only if raw_json is provided)
|
# Validation Task (Only if raw_json is provided)
|
||||||
if raw_json is not None:
|
if raw_json is not None:
|
||||||
prompt_lines.append("=== Validation Task ===")
|
|
||||||
prompt_lines.append(
|
|
||||||
"We have an existing JSON that may be malformed or incomplete. Validate and correct if needed."
|
|
||||||
)
|
|
||||||
prompt_lines.append("")
|
prompt_lines.append("")
|
||||||
prompt_lines.append("=== JSON to Validate ===")
|
prompt_lines.append("=== Validation Task ===")
|
||||||
|
prompt_lines.append("Validate and correct the following JSON if needed:")
|
||||||
prompt_lines.append(json.dumps(raw_json, indent=2))
|
prompt_lines.append(json.dumps(raw_json, indent=2))
|
||||||
prompt_lines.append("")
|
prompt_lines.append("")
|
||||||
prompt_lines.append("Validation Checks:")
|
|
||||||
prompt_lines.append("1. Fix any JSON syntax errors.")
|
|
||||||
prompt_lines.append("2. Ensure 'tool' is one of the defined tools or 'none'.")
|
|
||||||
prompt_lines.append(
|
prompt_lines.append(
|
||||||
"3. Check 'args' matches the required arguments for that tool; fill in from context or set null if unknown."
|
"Check syntax, ensure 'tool' is correct or 'null', verify 'args' are valid, "
|
||||||
)
|
'and set "next" appropriately based on missing or complete args.'
|
||||||
prompt_lines.append("4. Ensure 'response' is present (plain user-facing text).")
|
|
||||||
prompt_lines.append(
|
|
||||||
"5. Ensure 'next' is one of 'question', 'confirm', 'done'. "
|
|
||||||
"Use 'question' if required args are still null, 'confirm' if all args are set, "
|
|
||||||
"and 'done' if no more actions remain."
|
|
||||||
)
|
|
||||||
prompt_lines.append(
|
|
||||||
"6. Use the conversation history to see if arguments can be inferred."
|
|
||||||
)
|
|
||||||
prompt_lines.append(
|
|
||||||
"7. Return only the fixed JSON if changes are required, with no extra commentary."
|
|
||||||
)
|
)
|
||||||
|
prompt_lines.append("Return only the corrected JSON, no extra text.")
|
||||||
|
|
||||||
# Final Guidance
|
# Common Reminders and Examples
|
||||||
|
prompt_lines.append("")
|
||||||
|
prompt_lines.append("=== Usage Examples ===")
|
||||||
|
prompt_lines.append(
|
||||||
|
"Example for missing args (needs user input):\n"
|
||||||
|
"{\n"
|
||||||
|
' "response": "I need your departure city.",\n'
|
||||||
|
' "next": "question",\n'
|
||||||
|
' "tool": "SearchFlights",\n'
|
||||||
|
' "args": {\n'
|
||||||
|
' "origin": null,\n'
|
||||||
|
' "destination": "Melbourne",\n'
|
||||||
|
' "dateDepart": "2025-03-26",\n'
|
||||||
|
' "dateReturn": "2025-04-20"\n'
|
||||||
|
" }\n"
|
||||||
|
"}"
|
||||||
|
)
|
||||||
|
prompt_lines.append(
|
||||||
|
"Example for confirmed args:\n"
|
||||||
|
"{\n"
|
||||||
|
' "response": "All arguments are set.",\n'
|
||||||
|
' "next": "confirm",\n'
|
||||||
|
' "tool": "SearchFlights",\n'
|
||||||
|
' "args": {\n'
|
||||||
|
' "origin": "Seattle",\n'
|
||||||
|
' "destination": "Melbourne",\n'
|
||||||
|
' "dateDepart": "2025-03-26",\n'
|
||||||
|
' "dateReturn": "2025-04-20"\n'
|
||||||
|
" }\n"
|
||||||
|
"}"
|
||||||
|
)
|
||||||
|
prompt_lines.append(
|
||||||
|
"Example when fully done:\n"
|
||||||
|
"{\n"
|
||||||
|
' "response": "All tools completed successfully. Final result: <insert result here>",\n'
|
||||||
|
' "next": "done",\n'
|
||||||
|
' "tool": "",\n'
|
||||||
|
' "args": {}\n'
|
||||||
|
"}"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Prompt Start
|
||||||
if raw_json is not None:
|
if raw_json is not None:
|
||||||
prompt_lines.append("")
|
prompt_lines.append("")
|
||||||
prompt_lines.append(
|
prompt_lines.append("Begin by validating the provided JSON if necessary.")
|
||||||
"Begin by validating (and correcting) the JSON above, if needed."
|
|
||||||
)
|
|
||||||
else:
|
else:
|
||||||
prompt_lines.append("")
|
prompt_lines.append("")
|
||||||
prompt_lines.append(
|
prompt_lines.append(
|
||||||
"Begin by generating a valid JSON response for the next step."
|
"Begin by producing a valid JSON response for the next step."
|
||||||
)
|
)
|
||||||
|
|
||||||
prompt_lines.append(
|
|
||||||
"REMINDER: If any required argument is missing, set 'next': 'question' and ask the user for it. "
|
|
||||||
"REMINDER: Use 'next': 'confirm' only if NO arguments are missing. "
|
|
||||||
)
|
|
||||||
prompt_lines.append(
|
|
||||||
"""
|
|
||||||
Example JSON for question:
|
|
||||||
{
|
|
||||||
"args": {
|
|
||||||
"dateDepart": "2025-03-26",
|
|
||||||
"dateReturn": "2025-04-20",
|
|
||||||
"destination": "Melbourne",
|
|
||||||
"origin": null
|
|
||||||
},
|
|
||||||
"next": "question",
|
|
||||||
"response": "I need to know where you're flying from. What's your departure city?",
|
|
||||||
"tool": "SearchFlights"
|
|
||||||
}
|
|
||||||
"""
|
|
||||||
)
|
|
||||||
|
|
||||||
return "\n".join(prompt_lines)
|
return "\n".join(prompt_lines)
|
||||||
|
|||||||
@@ -4,4 +4,5 @@ def create_invoice(args: dict) -> dict:
|
|||||||
return {
|
return {
|
||||||
"invoiceStatus": "generated",
|
"invoiceStatus": "generated",
|
||||||
"invoiceURL": "https://pay.example.com/invoice/12345",
|
"invoiceURL": "https://pay.example.com/invoice/12345",
|
||||||
|
"reference": "INV-12345",
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,8 +16,8 @@ def search_flights(args: dict) -> dict:
|
|||||||
return {
|
return {
|
||||||
"tool": "SearchFlights",
|
"tool": "SearchFlights",
|
||||||
"searchResults": [
|
"searchResults": [
|
||||||
"QF 123: $1200",
|
"QF123: $1200",
|
||||||
"VA 456: $1000",
|
"VA456: $1000",
|
||||||
],
|
],
|
||||||
"status": "search-complete",
|
"status": "search-complete",
|
||||||
"args": args,
|
"args": args,
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ search_flights_tool = ToolDefinition(
|
|||||||
# 3) Define the CreateInvoice tool
|
# 3) Define the CreateInvoice tool
|
||||||
create_invoice_tool = ToolDefinition(
|
create_invoice_tool = ToolDefinition(
|
||||||
name="CreateInvoice",
|
name="CreateInvoice",
|
||||||
description="Generate an invoice with flight information or other items to purchase",
|
description="Generate an invoice with flight information.",
|
||||||
arguments=[
|
arguments=[
|
||||||
ToolArgument(
|
ToolArgument(
|
||||||
name="amount",
|
name="amount",
|
||||||
@@ -58,7 +58,7 @@ create_invoice_tool = ToolDefinition(
|
|||||||
ToolArgument(
|
ToolArgument(
|
||||||
name="flightDetails",
|
name="flightDetails",
|
||||||
type="string",
|
type="string",
|
||||||
description="A summary of the flights, e.g., flight numbers, price breakdown",
|
description="A summary of the flights, e.g., flight number and airport codes",
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -81,8 +81,10 @@ class ToolWorkflow:
|
|||||||
# Enqueue a follow-up prompt for the LLM
|
# Enqueue a follow-up prompt for the LLM
|
||||||
self.prompt_queue.append(
|
self.prompt_queue.append(
|
||||||
f"### The '{current_tool}' tool completed successfully with {dynamic_result}. "
|
f"### The '{current_tool}' tool completed successfully with {dynamic_result}. "
|
||||||
"INSTRUCTIONS: Use this tool result, and the conversation history to figure out next steps. "
|
"INSTRUCTIONS: Use this tool result, and the conversation history to figure out next steps, if any. "
|
||||||
"IMPORTANT: If all listed tools have run, you are up to the final step. Mark 'next':'done' and respond with 'All tools run' or similar."
|
"IMPORTANT REMINDER: Always return only JSON in the format: {'response': '', 'next': '', 'tool': '', 'args': {}} "
|
||||||
|
" Do NOT include any metadata or editorializing in the response. "
|
||||||
|
"IMPORTANT: If moving on to another tool then ensure you ask next='question' for any missing arguments."
|
||||||
)
|
)
|
||||||
# Loop around again
|
# Loop around again
|
||||||
continue
|
continue
|
||||||
@@ -91,15 +93,15 @@ class ToolWorkflow:
|
|||||||
if self.prompt_queue:
|
if self.prompt_queue:
|
||||||
prompt = self.prompt_queue.popleft()
|
prompt = self.prompt_queue.popleft()
|
||||||
if prompt.startswith("###"):
|
if prompt.startswith("###"):
|
||||||
# this is a custom prompt where the tool result is sent to the LLM
|
pass
|
||||||
self.add_message("tool_result_to_llm", prompt)
|
|
||||||
else:
|
else:
|
||||||
self.add_message("user", prompt)
|
self.add_message("user", prompt)
|
||||||
|
|
||||||
# Pass entire conversation + Tools to LLM
|
# Pass entire conversation + Tools to LLM
|
||||||
context_instructions = generate_genai_prompt(
|
context_instructions = generate_genai_prompt(
|
||||||
tools_data, self.format_history(), self.tool_data
|
tools_data, self.conversation_history, self.tool_data
|
||||||
)
|
)
|
||||||
|
|
||||||
prompt_input = ToolPromptInput(
|
prompt_input = ToolPromptInput(
|
||||||
prompt=prompt,
|
prompt=prompt,
|
||||||
context_instructions=context_instructions,
|
context_instructions=context_instructions,
|
||||||
|
|||||||
Reference in New Issue
Block a user