Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
@@ -26,8 +26,14 @@ llm = ChatOpenAI(model_name="gpt-4.1")
|
|
26 |
|
27 |
# agent = create_react_agent(model=llm, tools=tool_node)
|
28 |
|
29 |
-
# ─── 2) Revised plan_node ───
|
30 |
def plan_node(state: AgentState) -> AgentState:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
31 |
prior_msgs = state.get("messages", [])
|
32 |
user_input = ""
|
33 |
for msg in reversed(prior_msgs):
|
@@ -35,62 +41,63 @@ def plan_node(state: AgentState) -> AgentState:
|
|
35 |
user_input = msg.content
|
36 |
break
|
37 |
|
38 |
-
# (1) Build
|
39 |
system_msg = SystemMessage(
|
40 |
content=(
|
41 |
-
"You are an agent that
|
42 |
-
"
|
43 |
-
"
|
44 |
-
"•
|
45 |
-
"
|
46 |
-
"
|
47 |
-
"
|
48 |
-
"
|
49 |
-
"
|
50 |
-
"
|
|
|
|
|
|
|
|
|
|
|
|
|
51 |
)
|
52 |
)
|
53 |
human_msg = HumanMessage(content=user_input)
|
54 |
|
55 |
-
# (2) Call the LLM
|
56 |
-
llm_response = llm
|
57 |
llm_out = llm_response.content.strip()
|
58 |
|
59 |
-
#
|
60 |
-
# print("\n>>> plan_node got raw LLM output:")
|
61 |
-
# print(llm_out)
|
62 |
-
# print("<<< end raw output\n")
|
63 |
-
|
64 |
-
# (3) Append the LLM output to the message history
|
65 |
ai_msg = AIMessage(content=llm_out)
|
66 |
new_msgs = prior_msgs.copy() + [ai_msg]
|
67 |
|
68 |
-
# (4)
|
69 |
try:
|
70 |
parsed = json.loads(llm_out)
|
71 |
-
# print(">>> plan_node parsed JSON:", parsed)
|
72 |
if isinstance(parsed, dict):
|
73 |
partial: AgentState = {"messages": new_msgs}
|
74 |
-
|
|
|
|
|
75 |
"web_search_query",
|
76 |
"ocr_path",
|
77 |
"excel_path",
|
78 |
"excel_sheet_name",
|
79 |
-
"audio_path"
|
80 |
-
"wiki_query",
|
81 |
-
"final_answer"
|
82 |
}
|
83 |
for k, v in parsed.items():
|
84 |
-
if k in
|
85 |
partial[k] = v
|
86 |
-
# print(f">>> plan_node is setting {k!r} → {v!r}")
|
87 |
return partial
|
88 |
-
except json.JSONDecodeError
|
89 |
-
# print(">>> plan_node JSON parse error:", e)
|
90 |
pass
|
91 |
-
|
92 |
-
#
|
93 |
-
return {
|
|
|
|
|
|
|
94 |
|
95 |
|
96 |
|
|
|
26 |
|
27 |
# agent = create_react_agent(model=llm, tools=tool_node)
|
28 |
|
|
|
29 |
def plan_node(state: AgentState) -> AgentState:
|
30 |
+
"""
|
31 |
+
This plan_node will ask GPT to:
|
32 |
+
1) First write a concise *direct* answer.
|
33 |
+
2) Then decide whether it’s confident enough to stop (return {"final_answer": ...})
|
34 |
+
or if it needs to verify via one tool (return exactly one of {"wiki_query":...},
|
35 |
+
{"web_search_query":...}, {"ocr_path":...}, {"excel_path":...,"excel_sheet_name":...}, or {"audio_path":...}).
|
36 |
+
"""
|
37 |
prior_msgs = state.get("messages", [])
|
38 |
user_input = ""
|
39 |
for msg in reversed(prior_msgs):
|
|
|
41 |
user_input = msg.content
|
42 |
break
|
43 |
|
44 |
+
# (1) Build a fresh SystemMessage that tells the LLM exactly how to self‐evaluate
|
45 |
system_msg = SystemMessage(
|
46 |
content=(
|
47 |
+
"You are an agent that must do two things in a single JSON output:\n\n"
|
48 |
+
" 1) Produce a concise, direct answer to the user’s question (no explanation, just the answer). \n"
|
49 |
+
" 2) Judge whether that answer is reliable. \n"
|
50 |
+
" • If you are fully confident and do NOT need any external verification, return exactly:\n"
|
51 |
+
" {\"final_answer\":\"<your concise answer>\"}\n"
|
52 |
+
" and nothing else.\n"
|
53 |
+
" • If you think you need to verify or look something up first, return exactly one of the following (and nothing else):\n"
|
54 |
+
" {\"wiki_query\":\"<search terms for Wikipedia>\"}\n"
|
55 |
+
" {\"web_search_query\":\"<search terms>\"}\n"
|
56 |
+
" {\"ocr_path\":\"<local image path or task_id>\"}\n"
|
57 |
+
" {\"excel_path\":\"<local .xlsx path>\", \"excel_sheet_name\":\"<sheet name>\"}\n"
|
58 |
+
" {\"audio_path\":\"<local audio path or task_id>\"}\n\n"
|
59 |
+
" You must pick exactly one key—either final_answer or exactly one tool key.\n"
|
60 |
+
" Do NOT wrap it in any markdown or extra text. Only output a single JSON object.\n"
|
61 |
+
"\n"
|
62 |
+
f"User’s question: \"{user_input}\"\n"
|
63 |
)
|
64 |
)
|
65 |
human_msg = HumanMessage(content=user_input)
|
66 |
|
67 |
+
# (2) Call the LLM with this single system/human pair
|
68 |
+
llm_response = llm([system_msg, human_msg])
|
69 |
llm_out = llm_response.content.strip()
|
70 |
|
71 |
+
# (3) Append the LLM output into the message history
|
|
|
|
|
|
|
|
|
|
|
72 |
ai_msg = AIMessage(content=llm_out)
|
73 |
new_msgs = prior_msgs.copy() + [ai_msg]
|
74 |
|
75 |
+
# (4) Attempt to parse that JSON
|
76 |
try:
|
77 |
parsed = json.loads(llm_out)
|
|
|
78 |
if isinstance(parsed, dict):
|
79 |
partial: AgentState = {"messages": new_msgs}
|
80 |
+
allowed_keys = {
|
81 |
+
"final_answer",
|
82 |
+
"wiki_query",
|
83 |
"web_search_query",
|
84 |
"ocr_path",
|
85 |
"excel_path",
|
86 |
"excel_sheet_name",
|
87 |
+
"audio_path"
|
|
|
|
|
88 |
}
|
89 |
for k, v in parsed.items():
|
90 |
+
if k in allowed_keys:
|
91 |
partial[k] = v
|
|
|
92 |
return partial
|
93 |
+
except json.JSONDecodeError:
|
|
|
94 |
pass
|
95 |
+
|
96 |
+
# (5) If parsing failed, fall back to a safe “sorry” answer
|
97 |
+
return {
|
98 |
+
"messages": new_msgs,
|
99 |
+
"final_answer": "Sorry, I could not parse your intent."
|
100 |
+
}
|
101 |
|
102 |
|
103 |
|