fix: add context to prompt, get actionable
This commit is contained in:
@@ -26,11 +26,12 @@ class Captain::SummaryService < Captain::BaseTaskService
|
||||
end
|
||||
|
||||
def generate_and_cache_summary
|
||||
msg_count = conversation_message_count
|
||||
result = make_api_call(
|
||||
model: GPT_MODEL,
|
||||
model: summary_model(msg_count),
|
||||
messages: [
|
||||
{ role: 'system', content: prompt_from_file('summary') },
|
||||
{ role: 'user', content: conversation.to_llm_text(include_contact_details: false) }
|
||||
{ role: 'user', content: build_summary_content(msg_count) }
|
||||
]
|
||||
)
|
||||
|
||||
@@ -39,6 +40,41 @@ class Captain::SummaryService < Captain::BaseTaskService
|
||||
result
|
||||
end
|
||||
|
||||
def conversation_message_count
|
||||
conversation.messages.where(message_type: [:incoming, :outgoing]).count
|
||||
end
|
||||
|
||||
def summary_model(msg_count)
|
||||
msg_count < 7 ? GPT_MODEL : 'gpt-4.1'
|
||||
end
|
||||
|
||||
def build_summary_content(msg_count)
|
||||
llm_text = conversation.to_llm_text(include_contact_details: false)
|
||||
context = build_conversation_context(msg_count)
|
||||
context.present? ? "#{llm_text}\n\n#{context}" : llm_text
|
||||
end
|
||||
|
||||
def build_conversation_context(msg_count)
|
||||
['Conversation Stats:', *context_fields(msg_count).compact].join("\n")
|
||||
end
|
||||
|
||||
def context_fields(msg_count)
|
||||
[
|
||||
"Message count: #{msg_count}",
|
||||
("Status: #{conversation.status}" if conversation.status.present?),
|
||||
("Priority: #{conversation.priority}" if conversation.priority.present?),
|
||||
("Labels: #{conversation.cached_label_list}" if conversation.cached_label_list.present?),
|
||||
*account_context_fields
|
||||
]
|
||||
end
|
||||
|
||||
def account_context_fields
|
||||
[
|
||||
("Account industry: #{account.custom_attributes['industry']}" if account.custom_attributes&.dig('industry').present?),
|
||||
("Account language: #{account.locale}" if account.locale.present?)
|
||||
]
|
||||
end
|
||||
|
||||
def cache_summary(summary)
|
||||
conversation.update(
|
||||
cached_summary: summary,
|
||||
|
||||
@@ -2,19 +2,29 @@
|
||||
<role>AI support conversation summarizer</role>
|
||||
|
||||
<goal>
|
||||
Produce a high-signal summary that lets a new agent understand the CURRENT STATE in under 10 seconds.
|
||||
Produce a high-signal bullet summary that lets a new agent understand the CURRENT STATE and know what to do next — in under 10 seconds.
|
||||
Earlier bullets convey what happened and what the current state is. The final bullet is always the actionable next step.
|
||||
</goal>
|
||||
|
||||
<output_contract>
|
||||
<format>bullet_list</format>
|
||||
<only_output_bullets>true</only_output_bullets>
|
||||
<max_bullets>10</max_bullets>
|
||||
<bullet_count_rules>
|
||||
<rule>Count the messages in the conversation to determine bullet limits.</rule>
|
||||
<rule>1-3 messages → 1 bullet max</rule>
|
||||
<rule>4-10 messages → 2-3 bullets max</rule>
|
||||
<rule>11-30 messages → 3-4 bullets max</rule>
|
||||
<rule>31+ messages → 5-6 bullets max</rule>
|
||||
</bullet_count_rules>
|
||||
<bullet_rules>
|
||||
<single_sentence>true</single_sentence>
|
||||
<concise>true</concise>
|
||||
<no_redundancy>true</no_redundancy>
|
||||
<no_prefixes>Do not prefix bullets with labels like "Next step:" or "Issue:" — ordering alone conveys structure.</no_prefixes>
|
||||
</bullet_rules>
|
||||
<language>same_as_user</language>
|
||||
<language>
|
||||
<rule>If an agent locale is provided in the context, write the summary in that language.</rule>
|
||||
</language>
|
||||
<markdown>
|
||||
<bold_required>true</bold_required>
|
||||
<code_in_backticks>true</code_in_backticks>
|
||||
@@ -27,27 +37,35 @@
|
||||
<item>What is the customer trying to achieve right now?</item>
|
||||
<item>What is the current blocker/problem?</item>
|
||||
<item>What has already been done that changed the state?</item>
|
||||
<item>What is the explicitly stated next step (who does what)?</item>
|
||||
<item>What is the actionable next step (who does what)?</item>
|
||||
</priority_order>
|
||||
<skip_rule>If a priority item has no evidence in the conversation, skip it entirely — do not invent or guess.</skip_rule>
|
||||
<last_bullet_rule>The final bullet must always be an actionable next step derived from the conversation.</last_bullet_rule>
|
||||
</what_to_capture>
|
||||
|
||||
<context_awareness>
|
||||
<business_context>If account industry or business context is provided, adapt the summary focus accordingly (e.g., e-commerce → order/payment/shipping; SaaS → features/bugs/subscriptions; healthcare → appointments/records).</business_context>
|
||||
<labels>If conversation labels are provided, use them to understand the issue category and focus the summary on what matters for that category.</labels>
|
||||
<adapt>Only use context that is explicitly provided. Do not assume industry or category if not stated.</adapt>
|
||||
</context_awareness>
|
||||
|
||||
<importance_filter>
|
||||
<include_only_if_actionable_or_state_changing>
|
||||
<rule>A bullet must describe a blocker, a confirmed action taken, a decision, or a required next step.</rule>
|
||||
<rule>If a detail does not help an agent act or understand the blocker, omit it.</rule>
|
||||
<rule>Would removing this bullet prevent the agent from acting correctly? If no, omit it.</rule>
|
||||
</include_only_if_actionable_or_state_changing>
|
||||
<drop_as_noise>
|
||||
<item>Greetings, thanks, apologies, pleasantries, offers of help.</item>
|
||||
<item>Repeated statements that do not add new information.</item>
|
||||
<item>Meta commentary like “the current blocker is…” if it repeats an earlier bullet.</item>
|
||||
<item>Meta commentary like "the current blocker is…" if it repeats an earlier bullet.</item>
|
||||
</drop_as_noise>
|
||||
</importance_filter>
|
||||
|
||||
<anti_hallucination>
|
||||
<hard_rules>
|
||||
<item>Use ONLY information explicitly present in the conversation.</item>
|
||||
<item>Do NOT compute or derive facts (no time math like “15 minutes from now”, no inferred causes).</item>
|
||||
<item>Do NOT invent resolution, closure, or “no further steps” statements.</item>
|
||||
<item>Do NOT compute or derive facts (no time math like "15 minutes from now", no inferred causes).</item>
|
||||
<item>Do NOT invent resolution, closure, or "no further steps" statements.</item>
|
||||
<item>Do NOT restate the same fact in multiple bullets; merge into one.</item>
|
||||
</hard_rules>
|
||||
</anti_hallucination>
|
||||
@@ -61,7 +79,7 @@
|
||||
</examples>
|
||||
</bold_usage>
|
||||
<role_words>
|
||||
<rule>Prefer **Customer** and **Agent** over “user” and “support agent”.</rule>
|
||||
<rule>Prefer **Customer** and **Agent** over "user" and "support agent".</rule>
|
||||
</role_words>
|
||||
</formatting_rules>
|
||||
|
||||
@@ -71,7 +89,9 @@
|
||||
<item>Every bullet contains at least one **bold** phrase.</item>
|
||||
<item>No bullet contains inferred/derived info.</item>
|
||||
<item>No two bullets repeat the same meaning.</item>
|
||||
<item>Bullets reflect current state and next action (if explicitly stated).</item>
|
||||
<item>Last bullet is an actionable next step.</item>
|
||||
<item>Summary language matches agent locale (if provided) or conversation language.</item>
|
||||
<item>Bullet count respects the scaling rules for the message count.</item>
|
||||
</checklist>
|
||||
<reject_if_fails>true</reject_if_fails>
|
||||
</final_validation>
|
||||
|
||||
Reference in New Issue
Block a user