feat: support human in the loop

This commit is contained in:
He Tao 2025-04-14 18:01:50 +08:00
parent a759c168fa
commit a7ae47fc7a
12 changed files with 329 additions and 21 deletions

13
.vscode/launch.json vendored
View File

@ -33,6 +33,17 @@
"env": {
"PYTHONPATH": "${workspaceFolder}"
}
}
},
{
"name": "Python: server.py",
"type": "debugpy",
"request": "launch",
"program": "${workspaceFolder}/server.py",
"console": "integratedTerminal",
"justMyCode": true,
"env": {
"PYTHONPATH": "${workspaceFolder}"
}
},
]
}

View File

@ -152,6 +152,10 @@ The following examples demonstrate the capabilities of lite-deep-researcher:
- Discusses vulnerabilities of classical cryptography, post-quantum cryptography, and quantum-resistant cryptographic solutions
- [View full report](examples/Quantum_Computing_Impact_on_Cryptography.md)
9. **Cristiano Ronaldo's Performance Highlights** - Analysis of Cristiano Ronaldo's performance highlights
- Discusses his career achievements, international goals, and performance in various matches
- [View full report](examples/Cristiano_Ronaldo's_Performance_Highlights.md)
To run these examples or create your own research reports, you can use the following commands:
```bash
@ -186,6 +190,30 @@ The application now supports an interactive mode with built-in questions in both
4. The system will process your question and generate a comprehensive research report
### Human in the Loop
Lite-deep-researcher includes a human in the loop mechanism that allows you to review, edit, and approve research plans before they are executed:
1. **Plan Review**: When human in the loop is enabled, the system will present the generated research plan for your review before execution
2. **Providing Feedback**: You can:
- Accept the plan by responding with `[ACCEPTED]`
- Edit the plan by providing feedback (e.g., `[EDIT PLAN] Add more steps about technical implementation`)
- The system will incorporate your feedback and generate a revised plan
3. **Auto-acceptance**: You can enable auto-acceptance to skip the review process:
- Via API: Set `auto_accepted_plan: true` in your request
4. **API Integration**: When using the API, you can provide feedback through the `feedback` parameter:
```json
{
"messages": [{"role": "user", "content": "What is quantum computing?"}],
"thread_id": "my_thread_id",
"auto_accepted_plan": false,
"feedback": "[EDIT PLAN] Include more about quantum algorithms"
}
```
### Command Line Arguments
The application supports several command-line arguments to customize its behavior:

Binary file not shown.

Before

Width:  |  Height:  |  Size: 177 KiB

After

Width:  |  Height:  |  Size: 151 KiB

View File

@ -1,15 +1,15 @@
# LLM Config
REASONING_MODEL:
model: "qwq-plus"
api_key: sk-xxx
base_url: https://dashscope.aliyuncs.com/compatible-mode/v1
model: "gemini-2.0-flash"
api_key: xxxx
base_url: https://generativelanguage.googleapis.com/v1beta/openai/
BASIC_MODEL:
model: "qwen-max"
api_key: sk-xxx
base_url: https://dashscope.aliyuncs.com/compatible-mode/v1
model: "gemini-2.0-flash"
api_key: xxxx
base_url: https://generativelanguage.googleapis.com/v1beta/openai/
VISION_MODEL:
model: "qwen2.5-vl-32b-instruct"
api_key: sk-xxx
base_url: https://dashscope.aliyuncs.com/compatible-mode/v1
model: "gemini-2.0-flash"
api_key: xxxx
base_url: https://generativelanguage.googleapis.com/v1beta/openai/

View File

@ -0,0 +1,74 @@
# SSE Integration Test
## Auto Accepted Case
```
curl --location 'http://localhost:8000/api/chat/stream' \
--header 'Accept: */*' \
--header 'Accept-Language: en-US,en;q=0.9,zh-CN;q=0.8,zh;q=0.7' \
--header 'Cache-Control: no-cache' \
--header 'Connection: keep-alive' \
--header 'Content-Type: application/json' \
--data '{
"messages": [
{
"role": "user",
"content": "what is mcp?"
}
],
"thread_id": "test_thread_1",
"auto_accepted_plan": true
}'
```
## Human in the Loop Case
### Initial Plan
```
curl --location 'http://localhost:8000/api/chat/stream' \
--header 'Accept: */*' \
--header 'Accept-Language: en-US,en;q=0.9,zh-CN;q=0.8,zh;q=0.7' \
--header 'Cache-Control: no-cache' \
--header 'Connection: keep-alive' \
--header 'Content-Type: application/json' \
--data '{
"messages": [
{
"role": "user",
"content": "what is mcp?"
}
],
"thread_id": "test_thread_2",
"auto_accepted_plan": false
}'
```
### Edit the plan
```
{
"messages": [
{
"role": "user",
"content": "what is mcp?"
}
],
"thread_id": "test_thread_2",
"auto_accepted_plan": false,
"feedback": "[EDIT PLAN] make the last step be comprehensive"
}
```
### Accepted the plan
```
{
"messages": [
{
"role": "user",
"content": "what is mcp?"
}
],
"thread_id": "test_thread_2",
"auto_accepted_plan": false,
"feedback": "[ACCEPTED]"
}
```

View File

@ -0,0 +1,146 @@
# Cristiano Ronaldo's Performance Highlights
## Key Points
- Cristiano Ronaldo is Portugal's all-time top scorer with **136 goals** and record appearance maker with **219 caps** as of March 23, 2025.
- He holds the record for most goals in the UEFA Champions League (140), most international goals (136), and most appearances for a national team (219).
- Ronaldo has won the UEFA European Championship (2016) and the UEFA Nations League (2019) with Portugal.
- He has scored a record 924 senior career goals for club and country and has made over 1,250 professional career appearances.
- Ronaldo has won 5 Ballon d'Or awards, the most for a European player.
- He is the current captain of Portugal and has the most caps as captain for the team.
---
## Overview
Cristiano Ronaldo dos Santos Aveiro is widely regarded as one of the greatest football players of all time. Throughout his illustrious career, he has achieved remarkable success at both the club and international levels. This report highlights Ronaldo's performance milestones, records, and achievements, showcasing his impact on the sport.
---
## Detailed Analysis
### Sporting CP
Ronaldo began his professional career at Sporting CP, where he quickly gained attention for his skill and potential.
| Achievement | Description |
| ---------------- | ------------------------------------------------------------------------------------------ |
| Debut | Made his debut for Sporting CP's first team. |
| Manchester United Friendly | Played in a friendly match against Manchester United in 2003, impressing the English side. |
| Goals | Scored 5 goals for the club. |
### Manchester United
Ronaldo's move to Manchester United marked the beginning of his international stardom.
| Achievement | Description |
| --------------------- | --------------------------------------------------------------------------------------------- |
| Debut | Made his debut for Manchester United. |
| First Goal | Scored his first goal for the club. |
| Best Moments | Showcased exceptional performances and won multiple titles. |
### Real Madrid
At Real Madrid, Ronaldo reached new heights, becoming the club's all-time leading goalscorer.
| Achievement | Description |
| ---------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------- |
| Goals Scored | Scored 451 goals in 438 appearances. |
| Trophies Won | Won four Champions League titles, three Club World Cups, and two LaLiga titles. |
| All-Time Leading Goalscorer | Became the club's all-time leading goalscorer. |
### Juventus
Ronaldo continued his success at Juventus, winning Serie A titles and scoring consistently.
| Achievement | Description |
| --------------------- | ------------------------------------------------------------------------------------------------ |
| Goals Scored | Scored 101 goals in 134 appearances. |
| Key Performances | Notable performances include a double against Parma and a hat-trick against Atletico Madrid. |
### Al Nassr
Currently playing for Al Nassr, Ronaldo continues to add to his legacy.
| Achievement | Description |
| ---------------- | --------------------------------------------------------------------------- |
| AFC Champions League | Featured in matches in the AFC Champions League Elite. |
| Other Games | Played in various other games, contributing to the team's performance. |
### Portugal National Team
Ronaldo's international career is filled with records and achievements.
| Achievement | Description |
| --------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------ |
| Total Goals and Appearances | Portugal's record appearance maker with 219 caps and all-time top scorer with 136 goals as of March 23, 2025. |
| Goals in Competitive Matches | Scored 114 goals in competitive matches. |
| Trophies Won | Won the UEFA European Championship (2016) and the UEFA Nations League (2019). |
| Individual Awards | Named the Best Portuguese Player of All Time in 2015. |
| Major Tournament Statistics | Most games in the European Championship (30) and all-time leading scorer (14 goals). The only player to score at five different Euros. |
| Significant Match Performances | Scored twice against the Republic of Ireland on September 1, 2021, surpassing Ali Daei's record. |
| Records Broken | Holds the record for most goals scored in the history of international football, with 136 goals. |
| Captaincy and Leadership | Current captain of Portugal with the most caps as captain. |
| Other Records and Achievements | Won 5 Ballon d'Or awards, 3 UEFA Men's Player of the Year Awards, and 4 European Golden Shoes; Has won 33 trophies, including 7 league titles and 5 UEFA Champions Leagues |
---
## Key Citations
- [Cristiano Ronaldo Sporting CP Highlights | TikTok](https://www.tiktok.com/@sporting_cp/video/7339169970695228705?lang=en)
- [Cristiano Ronaldo Sporting Lisbon friendly highlights](https://www.manutd.com/en/videos/detail/cristiano-ronaldo-sporting-lisbon-friendly-highlights)
- [All 5 Goals For Sporting Lisbon - Cristiano Ronaldo - YouTube](https://www.youtube.com/watch?v=OBV57bqFvrw)
- [The Best of CR7 at Manchester United: 45 Minutes of Pure Magic ...](https://www.youtube.com/watch?v=Q9_NhdNLyBQ)
- [Cristiano Ronaldo's performance at Manchester United: 5 best moments at ...](https://www.elfutbolero.us/premier-league/cristiano-ronaldos-performance-at-manchester-united-5-best-moments-at-the-club-20241230-47146.html)
- [Manchester United Guide: Ronaldo's Career Highlights](https://unitedingratitude.aon.com/manchester-united-guide-ronaldos-career-highlights)
- [Cristiano Ronaldo's Real Madrid Highlights Gallery - Getty Images](https://www.gettyimages.com/sets/Un9jMk8A2kyZVnrlal2KXg/cristiano-ronaldo's-real-madrid-highlights)
- [Cristiano Ronaldo | Official Website | Real Madrid C.F.](https://www.realmadrid.com/en-US/the-club/history/football-legends/cristiano-ronaldo-dos-santos-aveiro)
- [Real Madrid 6 x 0 Espanyol (C. Ronaldo Hat-Trick) La Liga 15/16 ...](https://www.youtube.com/watch?v=RunxuA6wtHk&vl=en)
- [HIGHLIGHTS: Juventus vs Parma - 2-1 - Cristiano Ronaldo at the double ...](https://www.juventus.com/en/video/highlights-juventus-vs-parma-2-1-cristiano-ronaldo-at-the-double)
- [HIGHLIGHTS | Juventus 3-0 Atletico Madrid | Ronaldo greatest ... - YouTube](https://www.youtube.com/watch?v=cLfSpFg6Pxg)
- [REWIND | Cristiano Ronaldo's First for Juve - Juventus.com](https://www.juventus.com/en/news/articles/rewind-cristiano-ronaldo-s-first-for-juve)
- [Al Nassr (KSA) - Esteghlal FC (IRN) | Highlights ACL Elite™ - YouTube](https://www.youtube.com/watch?v=CUbYX4s-n8A)
- [Cristiano Ronaldo FINISHED? Al Orobah 2-1 Al Nassr HIGHLIGHTS](https://www.youtube.com/watch?v=FRhpTh0Eauk)
- [Ronaldo Brace! | Al Nassr (KSA) - Al Wasl FC (UAE) | Highlights](https://www.youtube.com/watch?v=Lyss81RSvBg)
- [Portugal national football team records and statistics - Wikipedia](https://en.wikipedia.org/wiki/Portugal_national_football_team_records_and_statistics)
- [The Records Cristiano Ronaldo Holds in Portugal National Team](https://setantasports.com/uncategorized/the-records-cristiano-ronaldo-holds-in-portugal-national-team/)
- [Cristiano Ronaldo - National team - Transfermarkt](https://www.transfermarkt.us/cristiano-ronaldo/nationalmannschaft/spieler/8198)
- [Cristiano Ronaldo's 136 international goals: Opposition, when they ...](https://www.uefa.com/uefanationsleague/news/0257-0e001aafb4e9-7c6ad3889ce0-7c6ad3889ce0)
- [Cristiano Ronaldo: All-time leading scorer in men's international ...](https://www.uefa.com/uefanationsleague/news/026a-1297500e1b34-a17bbbcad258-1000--cristiano-ronaldo-all-time-leading-scorer-in-men-s-interna/)
- [International Goals and Stats - Messi vs Ronaldo All Time ...](https://www.messivsronaldo.app/international-stats/)
- [List of career achievements by Cristiano Ronaldo - Wikipedia](https://en.wikipedia.org/wiki/List_of_career_achievements_by_Cristiano_Ronaldo)
- [Cristiano Ronaldo - Wikipedia](https://en.wikipedia.org/wiki/Cristiano_Ronaldo)
- [Trophies won by Cristiano Ronaldo 2024 - Statista](https://www.statista.com/statistics/1008294/cristiano-ronaldo-trophy-titles/)
- [[Statmuse] Cristiano Ronaldo major tournament career: 21 knockout ...](https://www.reddit.com/r/soccer/comments/1dw9r96/statmuse_cristiano_ronaldo_major_tournament/)
- [Cristiano Ronaldo | Stats | Portugal | UEFA EURO 2024](https://www.uefa.com/euro2024/teams/players/63706--cristiano-ronaldo/statistics/)
- [List of Portugal national football team captains - Wikipedia](https://en.wikipedia.org/wiki/List_of_Portugal_national_football_team_captains)
- [Ronaldo retains Portugal captaincy after Euro 2024](https://punchng.com/ronaldo-retains-portugal-captaincy-after-euro-2024/)
- [Euro 2024: Cristiano Ronaldo captains Portugal to become the first ...](https://www.marca.com/en/football/uefa-euro/2024/06/18/6671f709e2704ee6288b45b4.html)

View File

@ -8,6 +8,7 @@ from .nodes import (
research_team_node,
researcher_node,
coder_node,
human_feedback_node,
)
@ -26,5 +27,6 @@ def build_graph():
builder.add_node("research_team", research_team_node)
builder.add_node("researcher", researcher_node)
builder.add_node("coder", coder_node)
builder.add_node("human_feedback", human_feedback_node)
builder.add_edge("reporter", END)
return builder.compile(checkpointer=memory)

View File

@ -2,10 +2,10 @@ import logging
import json
from typing import Literal, Annotated
from langchain_core.messages import HumanMessage
from langchain_core.messages import HumanMessage, AIMessage
from langchain_core.tools import tool
from langchain_core.runnables import RunnableConfig
from langgraph.types import Command
from langgraph.types import Command, interrupt
from src.llms.llm import get_llm_by_type
from src.config.agents import AGENT_LLM_MAP
@ -31,7 +31,7 @@ def handoff_to_planner(
def planner_node(
state: State, config: RunnableConfig
) -> Command[Literal["research_team", "reporter", "__end__"]]:
) -> Command[Literal["human_feedback", "reporter"]]:
"""Planner node that generate the full plan."""
logger.info("Planner generating full plan")
configurable = Configuration.from_runnable_config(config)
@ -42,7 +42,6 @@ def planner_node(
)
else:
llm = get_llm_by_type(AGENT_LLM_MAP["planner"])
current_plan = state.get("current_plan", None)
plan_iterations = state["plan_iterations"] if state.get("plan_iterations", 0) else 0
# if the plan iterations is greater than the max plan iterations, return the reporter node
@ -60,13 +59,48 @@ def planner_node(
logger.debug(f"Current state messages: {state['messages']}")
logger.debug(f"Planner response: {full_response}")
return Command(
update={
"messages": [AIMessage(content=full_response, name="planner")],
"current_plan": full_response,
},
goto="human_feedback",
)
def human_feedback_node(
state,
) -> Command[Literal["planner", "research_team", "reporter", "__end__"]]:
current_plan = state.get("current_plan", "")
# check if the plan is auto accepted
auto_accepted_plan = state.get("auto_accepted_plan", False)
if not auto_accepted_plan:
feedback = interrupt(current_plan)
# if the feedback is not accepted, return the planner node
if feedback and str(feedback).upper() != "[ACCEPTED]":
return Command(
update={
"messages": [
HumanMessage(content=feedback, name="feedback"),
],
},
goto="planner",
)
elif feedback and str(feedback).upper() == "[ACCEPTED]":
logger.info("Plan is accepted by user.")
else:
raise TypeError(f"Interrupt value of {feedback} is not supported.")
# if the plan is accepted, run the following node
plan_iterations = state["plan_iterations"] if state.get("plan_iterations", 0) else 0
goto = "research_team"
try:
full_response = repair_json_output(full_response)
current_plan = repair_json_output(current_plan)
# increment the plan iterations
plan_iterations += 1
# parse the plan
new_plan = json.loads(full_response)
new_plan = json.loads(current_plan)
if new_plan["has_enough_context"]:
goto = "reporter"
except json.JSONDecodeError:
@ -78,8 +112,6 @@ def planner_node(
return Command(
update={
"messages": [HumanMessage(content=full_response, name="planner")],
"last_plan": current_plan,
"current_plan": Plan.model_validate(new_plan),
"plan_iterations": plan_iterations,
},

View File

@ -11,6 +11,6 @@ class State(MessagesState):
# Runtime Variables
observations: Annotated[list[str], operator.add] = []
plan_iterations: int = 0
last_plan: Plan = None
current_plan: Plan = None
current_plan: Plan | str = None
final_report: str = ""
auto_accepted_plan: bool = False

View File

@ -7,6 +7,7 @@ from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import StreamingResponse
from langchain_core.messages import AIMessageChunk, ToolMessage
from langgraph.types import Command
from src.graph.builder import build_graph
from src.server.chat_request import ChatMessage, ChatRequest
@ -42,6 +43,8 @@ async def chat_stream(request: ChatRequest):
thread_id,
request.max_plan_iterations,
request.max_step_num,
request.auto_accepted_plan,
request.feedback,
),
media_type="text/event-stream",
)
@ -52,9 +55,14 @@ async def _astream_workflow_generator(
thread_id: str,
max_plan_iterations: int,
max_step_num: int,
auto_accepted_plan: bool,
feedback: str,
):
input_ = {"messages": messages, "auto_accepted_plan": auto_accepted_plan}
if not auto_accepted_plan and feedback:
input_ = Command(resume=feedback)
async for agent, _, event_data in graph.astream(
{"messages": messages},
input_,
config={
"thread_id": thread_id,
"max_plan_iterations": max_plan_iterations,

View File

@ -35,3 +35,9 @@ class ChatRequest(BaseModel):
max_step_num: Optional[int] = Field(
3, description="The maximum number of steps in a plan"
)
auto_accepted_plan: Optional[bool] = Field(
False, description="Whether to automatically accept the plan"
)
feedback: Optional[str] = Field(
None, description="Feedback from the user on the plan"
)

View File

@ -46,6 +46,7 @@ def run_agent_workflow(
initial_state = {
# Runtime Variables
"messages": [{"role": "user", "content": user_input}],
"auto_accepted_plan": True,
}
config = {
"configurable": {