Files
deer-flow/main.py
jimmyuconn1982 2510cc61de feat: Add intelligent clarification feature in coordinate step for research queries (#613)
* fix: support local models by making thought field optional in Plan model

- Make thought field optional in Plan model to fix Pydantic validation errors with local models
- Add Ollama configuration example to conf.yaml.example
- Update documentation to include local model support
- Improve planner prompt with better JSON format requirements

Fixes local model integration issues where models like qwen3:14b would fail
due to missing thought field in JSON output.

* feat: Add intelligent clarification feature for research queries

- Add multi-turn clarification process to refine vague research questions
- Implement three-dimension clarification standard (Tech/App, Focus, Scope)
- Add clarification state management in coordinator node
- Update coordinator prompt with detailed clarification guidelines
- Add UI settings to enable/disable clarification feature (disabled by default)
- Update workflow to handle clarification rounds recursively
- Add comprehensive test coverage for clarification functionality
- Update documentation with clarification feature usage guide

Key components:
- src/graph/nodes.py: Core clarification logic and state management
- src/prompts/coordinator.md: Detailed clarification guidelines
- src/workflow.py: Recursive clarification handling
- web/: UI settings integration
- tests/: Comprehensive test coverage
- docs/: Updated configuration guide

* fix: Improve clarification conversation continuity

- Add comprehensive conversation history to clarification context
- Include previous exchanges summary in system messages
- Add explicit guidelines for continuing rounds in coordinator prompt
- Prevent LLM from starting new topics during clarification
- Ensure topic continuity across clarification rounds

Fixes issue where LLM would restart clarification instead of building upon previous exchanges.

* fix: Add conversation history to clarification context

* fix: resolve clarification feature message to planer, prompt, test issues

- Optimize coordinator.md prompt template for better clarification flow
- Simplify final message sent to planner after clarification
- Fix API key assertion issues in test_search.py

* fix: Add configurable max_clarification_rounds and comprehensive tests

- Add max_clarification_rounds parameter for external configuration
- Add comprehensive test cases for clarification feature in test_app.py
- Fixes issues found during interactive mode testing where:
  - Recursive call failed due to missing initial_state parameter
  - Clarification exited prematurely at max rounds
  - Incorrect logging of max rounds reached

* Move clarification tests to test_nodes.py and add max_clarification_rounds to zh.json
2025-10-14 13:35:57 +08:00

185 lines
6.2 KiB
Python

# Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
# SPDX-License-Identifier: MIT
"""
Entry point script for the DeerFlow project.
"""
import argparse
import asyncio
from InquirerPy import inquirer
from src.config.questions import BUILT_IN_QUESTIONS, BUILT_IN_QUESTIONS_ZH_CN
from src.workflow import run_agent_workflow_async
def ask(
question,
debug=False,
max_plan_iterations=1,
max_step_num=3,
enable_background_investigation=True,
enable_clarification=False,
max_clarification_rounds=None,
):
"""Run the agent workflow with the given question.
Args:
question: The user's query or request
debug: If True, enables debug level logging
max_plan_iterations: Maximum number of plan iterations
max_step_num: Maximum number of steps in a plan
enable_background_investigation: If True, performs web search before planning to enhance context
enable_clarification: If False (default), skip clarification; if True, enable multi-turn clarification
max_clarification_rounds: Maximum number of clarification rounds (default: None, uses State default=3)
"""
asyncio.run(
run_agent_workflow_async(
user_input=question,
debug=debug,
max_plan_iterations=max_plan_iterations,
max_step_num=max_step_num,
enable_background_investigation=enable_background_investigation,
enable_clarification=enable_clarification,
max_clarification_rounds=max_clarification_rounds,
)
)
def main(
debug=False,
max_plan_iterations=1,
max_step_num=3,
enable_background_investigation=True,
enable_clarification=False,
max_clarification_rounds=None,
):
"""Interactive mode with built-in questions.
Args:
enable_background_investigation: If True, performs web search before planning to enhance context
debug: If True, enables debug level logging
max_plan_iterations: Maximum number of plan iterations
max_step_num: Maximum number of steps in a plan
enable_clarification: If False (default), skip clarification; if True, enable multi-turn clarification
max_clarification_rounds: Maximum number of clarification rounds (default: None, uses State default=3)
"""
# First select language
language = inquirer.select(
message="Select language / 选择语言:",
choices=["English", "中文"],
).execute()
# Choose questions based on language
questions = (
BUILT_IN_QUESTIONS if language == "English" else BUILT_IN_QUESTIONS_ZH_CN
)
ask_own_option = (
"[Ask my own question]" if language == "English" else "[自定义问题]"
)
# Select a question
initial_question = inquirer.select(
message=(
"What do you want to know?" if language == "English" else "您想了解什么?"
),
choices=[ask_own_option] + questions,
).execute()
if initial_question == ask_own_option:
initial_question = inquirer.text(
message=(
"What do you want to know?"
if language == "English"
else "您想了解什么?"
),
).execute()
# Pass all parameters to ask function
ask(
question=initial_question,
debug=debug,
max_plan_iterations=max_plan_iterations,
max_step_num=max_step_num,
enable_background_investigation=enable_background_investigation,
enable_clarification=enable_clarification,
max_clarification_rounds=max_clarification_rounds,
)
if __name__ == "__main__":
# Set up argument parser
parser = argparse.ArgumentParser(description="Run the Deer")
parser.add_argument("query", nargs="*", help="The query to process")
parser.add_argument(
"--interactive",
action="store_true",
help="Run in interactive mode with built-in questions",
)
parser.add_argument(
"--max_plan_iterations",
type=int,
default=1,
help="Maximum number of plan iterations (default: 1)",
)
parser.add_argument(
"--max_step_num",
type=int,
default=3,
help="Maximum number of steps in a plan (default: 3)",
)
parser.add_argument("--debug", action="store_true", help="Enable debug logging")
parser.add_argument(
"--no-background-investigation",
action="store_false",
dest="enable_background_investigation",
help="Disable background investigation before planning",
)
parser.add_argument(
"--enable-clarification",
action="store_true",
dest="enable_clarification",
help="Enable multi-turn clarification for vague questions (default: disabled)",
)
parser.add_argument(
"--max-clarification-rounds",
type=int,
dest="max_clarification_rounds",
help="Maximum number of clarification rounds (default: 3)",
)
args = parser.parse_args()
if args.interactive:
# Pass command line arguments to main function
main(
debug=args.debug,
max_plan_iterations=args.max_plan_iterations,
max_step_num=args.max_step_num,
enable_background_investigation=args.enable_background_investigation,
enable_clarification=args.enable_clarification,
max_clarification_rounds=args.max_clarification_rounds,
)
else:
# Parse user input from command line arguments or user input
if args.query:
user_query = " ".join(args.query)
else:
# Loop until user provides non-empty input
while True:
user_query = input("Enter your query: ")
if user_query is not None and user_query != "":
break
# Run the agent workflow with the provided parameters
ask(
question=user_query,
debug=args.debug,
max_plan_iterations=args.max_plan_iterations,
max_step_num=args.max_step_num,
enable_background_investigation=args.enable_background_investigation,
enable_clarification=args.enable_clarification,
max_clarification_rounds=args.max_clarification_rounds,
)