Spaces:
Sleeping
Sleeping
Daniel Tu Claude Opus 4.6 (1M context) commited on
feat: constrain agent questions to user-friendly abstraction level (#13)
Browse filesAgents and gap analyzer were asking overly technical questions like
"What are the precise X, Y, Z coordinates for the M4 mounting holes?"
— details only a CAD engineer would know. Users describe intent; agents
should derive the technical parameters.
- Add question abstraction rules to gap analyzer system prompt
- Apply CrewAI system_template on advisory agents (design, engineering,
cnc) via {{ .System }} / {{ .Prompt }} to preserve default behaviour
while injecting question-level guidance
- Improve part name extraction patterns in DesignState
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- agents/agent_flow.py +31 -1
- agents/design_state.py +3 -1
- agents/gap_analyzer.py +21 -0
agents/agent_flow.py
CHANGED
|
@@ -28,6 +28,31 @@ logger = logging.getLogger(__name__)
|
|
| 28 |
WIKI_DIR = Path(__file__).parent.parent / "docs" / "wiki"
|
| 29 |
|
| 30 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 31 |
# ── Data models ───────────────────────────────────────────────────────────────
|
| 32 |
|
| 33 |
|
|
@@ -400,6 +425,9 @@ class AgentDispatchFlow(Flow[AgentFlowState]):
|
|
| 400 |
|
| 401 |
knowledge_sources = self._build_knowledge_sources() if agent_id in ("cnc", "cam") else []
|
| 402 |
|
|
|
|
|
|
|
|
|
|
| 403 |
crew_agent = Agent(
|
| 404 |
role=agent_def.role,
|
| 405 |
goal=agent_def.goal,
|
|
@@ -407,8 +435,10 @@ class AgentDispatchFlow(Flow[AgentFlowState]):
|
|
| 407 |
llm=llm,
|
| 408 |
tools=tools,
|
| 409 |
verbose=False,
|
| 410 |
-
allow_delegation=settings.crew.collaboration and
|
| 411 |
knowledge_sources=knowledge_sources if knowledge_sources else None,
|
|
|
|
|
|
|
| 412 |
)
|
| 413 |
|
| 414 |
memories = self._recall_for_agent(agent_id)
|
|
|
|
| 28 |
WIKI_DIR = Path(__file__).parent.parent / "docs" / "wiki"
|
| 29 |
|
| 30 |
|
| 31 |
+
# ── CrewAI prompt templates ─────────────────────────────────────────────────
|
| 32 |
+
# Applied via CrewAI's system_template / prompt_template on advisory agents.
|
| 33 |
+
# {{ .System }} expands to the default system slices (role_playing + tools);
|
| 34 |
+
# {{ .Prompt }} expands to the task slice. This preserves all default CrewAI
|
| 35 |
+
# behaviour (tool-use format, etc.) while injecting question-level guidance.
|
| 36 |
+
|
| 37 |
+
_ADVISOR_SYSTEM_TEMPLATE = """\
|
| 38 |
+
{{ .System }}
|
| 39 |
+
|
| 40 |
+
## Question Guidelines
|
| 41 |
+
When asking the user clarifying questions, follow these rules strictly:
|
| 42 |
+
- Ask questions a normal person can answer. The user describes INTENT; you derive the technical details.
|
| 43 |
+
- NEVER ask for exact coordinates, precise radii, specific tolerance values, or CAD-level parameters.
|
| 44 |
+
- Frame questions in everyday language and offer 2-4 plain-language suggestions.
|
| 45 |
+
- GOOD: "Where should the mounting holes go?" → "one in each corner", "evenly spaced along edges"
|
| 46 |
+
- BAD: "What are the precise X, Y, Z coordinates for the M4 mounting holes?"
|
| 47 |
+
- GOOD: "How thick should the walls be?" → "thin (1-2mm)", "standard (3-5mm)", "heavy-duty (6mm+)"
|
| 48 |
+
- BAD: "What is the minimum wall thickness in mm for the vertical ribs?"
|
| 49 |
+
- GOOD: "Should the edges be sharp or rounded?"
|
| 50 |
+
- BAD: "What fillet radius should be applied to the internal pocket edges?"
|
| 51 |
+
- You are the expert — infer technical parameters from the user's high-level answer."""
|
| 52 |
+
|
| 53 |
+
_ADVISOR_PROMPT_TEMPLATE = "{{ .Prompt }}"
|
| 54 |
+
|
| 55 |
+
|
| 56 |
# ── Data models ───────────────────────────────────────────────────────────────
|
| 57 |
|
| 58 |
|
|
|
|
| 425 |
|
| 426 |
knowledge_sources = self._build_knowledge_sources() if agent_id in ("cnc", "cam") else []
|
| 427 |
|
| 428 |
+
# Advisory agents get system_template with question-abstraction
|
| 429 |
+
# guidance via CrewAI's prompt customisation (see _ADVISOR_SYSTEM_TEMPLATE).
|
| 430 |
+
is_advisor = agent_id in ADVISOR_IDS
|
| 431 |
crew_agent = Agent(
|
| 432 |
role=agent_def.role,
|
| 433 |
goal=agent_def.goal,
|
|
|
|
| 435 |
llm=llm,
|
| 436 |
tools=tools,
|
| 437 |
verbose=False,
|
| 438 |
+
allow_delegation=settings.crew.collaboration and is_advisor,
|
| 439 |
knowledge_sources=knowledge_sources if knowledge_sources else None,
|
| 440 |
+
system_template=_ADVISOR_SYSTEM_TEMPLATE if is_advisor else None,
|
| 441 |
+
prompt_template=_ADVISOR_PROMPT_TEMPLATE if is_advisor else None,
|
| 442 |
)
|
| 443 |
|
| 444 |
memories = self._recall_for_agent(agent_id)
|
agents/design_state.py
CHANGED
|
@@ -240,7 +240,9 @@ class DesignState(BaseModel):
|
|
| 240 |
# Extract part name from user message if not set
|
| 241 |
if not state.part_name and user_message:
|
| 242 |
name_patterns = [
|
| 243 |
-
r'(?:need|want|design|make|create)\s+(?:a|an)\s+(.{
|
|
|
|
|
|
|
| 244 |
]
|
| 245 |
for pattern in name_patterns:
|
| 246 |
match = re.search(pattern, user_message, re.IGNORECASE)
|
|
|
|
| 240 |
# Extract part name from user message if not set
|
| 241 |
if not state.part_name and user_message:
|
| 242 |
name_patterns = [
|
| 243 |
+
r'(?:need|want|design|make|create|build|model)\s+(?:a|an|the)\s+(.{3,40}?)\s*(?:with|for|that|using|,|\.|$)',
|
| 244 |
+
r'(?:need|want|design|make|create|build|model)\s+(.{3,40}?)\s*(?:with|for|that|using|,|\.|$)',
|
| 245 |
+
r"(?:i'm|i am)\s+(?:building|making|designing)\s+(?:a|an|the)\s+(.{3,40}?)\s*(?:with|for|that|using|,|\.|$)",
|
| 246 |
]
|
| 247 |
for pattern in name_patterns:
|
| 248 |
match = re.search(pattern, user_message, re.IGNORECASE)
|
agents/gap_analyzer.py
CHANGED
|
@@ -62,6 +62,8 @@ what information is still missing to produce a complete CNC-ready design.
|
|
| 62 |
Rules:
|
| 63 |
- Do NOT flag gaps for information already present in the design state.
|
| 64 |
- Do NOT flag gaps for information the user just provided in their message.
|
|
|
|
|
|
|
| 65 |
- Invent descriptive category names (e.g. "bolt_pattern", "thermal_rating",
|
| 66 |
"load_capacity") — there is no fixed set.
|
| 67 |
- Use snake_case for category names.
|
|
@@ -73,6 +75,25 @@ Rules:
|
|
| 73 |
"design", "engineering", "cnc", "cad", or "cam".
|
| 74 |
- If no gaps exist, return has_gaps: false with empty lists.
|
| 75 |
- Set severity on each question card matching the gap it addresses.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 76 |
"""
|
| 77 |
|
| 78 |
|
|
|
|
| 62 |
Rules:
|
| 63 |
- Do NOT flag gaps for information already present in the design state.
|
| 64 |
- Do NOT flag gaps for information the user just provided in their message.
|
| 65 |
+
- Do NOT ask about the part name — the system derives it automatically.
|
| 66 |
+
- Do NOT repeat questions that were already asked in previous turns.
|
| 67 |
- Invent descriptive category names (e.g. "bolt_pattern", "thermal_rating",
|
| 68 |
"load_capacity") — there is no fixed set.
|
| 69 |
- Use snake_case for category names.
|
|
|
|
| 75 |
"design", "engineering", "cnc", "cad", or "cam".
|
| 76 |
- If no gaps exist, return has_gaps: false with empty lists.
|
| 77 |
- Set severity on each question card matching the gap it addresses.
|
| 78 |
+
|
| 79 |
+
Question abstraction level — CRITICAL:
|
| 80 |
+
- Ask questions a normal person can answer, NOT questions requiring CAD or
|
| 81 |
+
engineering expertise. The user describes INTENT; the agents derive the
|
| 82 |
+
technical implementation.
|
| 83 |
+
- NEVER ask for exact coordinates, precise radii, specific tolerance values,
|
| 84 |
+
G-code parameters, or CadQuery implementation details.
|
| 85 |
+
- GOOD: "Where should the mounting holes go?" with suggestions like
|
| 86 |
+
"one in each corner", "evenly spaced along the edges", "centered on top".
|
| 87 |
+
- BAD: "What are the precise X, Y, Z coordinates for the M4 mounting holes?"
|
| 88 |
+
- GOOD: "Should the edges be sharp or rounded?"
|
| 89 |
+
- BAD: "What fillet radius should be applied to the internal pocket edges?"
|
| 90 |
+
- GOOD: "How thick should the walls be?" with suggestions like "thin
|
| 91 |
+
(1-2mm)", "standard (3-5mm)", "heavy-duty (6mm+)".
|
| 92 |
+
- BAD: "What is the minimum wall thickness in mm for the vertical ribs?"
|
| 93 |
+
- Frame questions in everyday language. Offer 2-4 plain-language suggestions
|
| 94 |
+
that map to concrete engineering values behind the scenes.
|
| 95 |
+
- Technical details (coordinates, exact radii, tolerance classes, feed rates)
|
| 96 |
+
are the agents' job to determine from the user's high-level answers.
|
| 97 |
"""
|
| 98 |
|
| 99 |
|