Realistvik0 commited on
Commit
e6cb7bb
·
verified ·
1 Parent(s): c11c48d

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +237 -21
app.py CHANGED
@@ -1,6 +1,6 @@
1
  import yaml
2
 
3
- from smolagents import CodeAgent, HfApiModel
4
 
5
  from Gradio_UI import GradioUI
6
 
@@ -9,10 +9,13 @@ from tools.final_answer import FinalAnswerTool
9
  from tools.visit_webpage import VisitWebpageTool
10
  from tools.web_search import DuckDuckGoSearchTool
11
 
 
 
12
 
13
- # ---------------------------------------------------------
 
14
  # Configuration
15
- # ---------------------------------------------------------
16
 
17
  MODEL_ID = "Qwen/Qwen2.5-Coder-32B-Instruct"
18
 
@@ -21,40 +24,252 @@ MAX_TOKENS = 4096
21
  TEMPERATURE = 0.2
22
 
23
 
24
- # ---------------------------------------------------------
25
- # Load prompts
26
- # ---------------------------------------------------------
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
27
 
28
  with open("prompts.yaml", "r", encoding="utf-8") as stream:
29
  prompt_templates = yaml.safe_load(stream)
30
 
31
 
32
- # ---------------------------------------------------------
33
  # Tools
34
- # ---------------------------------------------------------
35
 
36
- web_search = DuckDuckGoSearchTool(
37
  max_results=10
38
  )
39
 
40
- visit_webpage = VisitWebpageTool()
41
 
42
  calculator = Calculator()
43
 
44
- final_answer = FinalAnswerTool()
45
 
 
46
 
47
  tools = [
48
  web_search,
49
  visit_webpage,
50
  calculator,
 
51
  final_answer,
52
  ]
53
 
54
 
55
- # ---------------------------------------------------------
56
  # Model
57
- # ---------------------------------------------------------
58
 
59
  model = HfApiModel(
60
  model_id=MODEL_ID,
@@ -64,9 +279,9 @@ model = HfApiModel(
64
  )
65
 
66
 
67
- # ---------------------------------------------------------
68
- # Research Agent
69
- # ---------------------------------------------------------
70
 
71
  agent = CodeAgent(
72
  model=model,
@@ -77,17 +292,18 @@ agent = CodeAgent(
77
  planning_interval=2,
78
  name="web_research_agent",
79
  description=(
80
- "A web research and fact-verification agent that searches "
81
- "for evidence, reads sources, performs calculations, "
82
- "checks conflicting claims, and produces cited answers."
 
83
  ),
84
  prompt_templates=prompt_templates,
85
  )
86
 
87
 
88
- # ---------------------------------------------------------
89
  # Launch
90
- # ---------------------------------------------------------
91
 
92
  if __name__ == "__main__":
93
  GradioUI(agent).launch()
 
1
  import yaml
2
 
3
+ from smolagents import CodeAgent, HfApiModel, Tool
4
 
5
  from Gradio_UI import GradioUI
6
 
 
9
  from tools.visit_webpage import VisitWebpageTool
10
  from tools.web_search import DuckDuckGoSearchTool
11
 
12
+ from research_state import ResearchState
13
+ from verifier import verify_research
14
 
15
+
16
+ # =========================================================
17
  # Configuration
18
+ # =========================================================
19
 
20
  MODEL_ID = "Qwen/Qwen2.5-Coder-32B-Instruct"
21
 
 
24
  TEMPERATURE = 0.2
25
 
26
 
27
+ # =========================================================
28
+ # Research Context
29
+ # =========================================================
30
+
31
+ class ResearchContext:
32
+ """
33
+ Holds the state for a single research run.
34
+
35
+ The context is shared by the research tools so that
36
+ searches, webpages, claims, and verification results
37
+ belong to the same research session.
38
+ """
39
+
40
+ def __init__(self):
41
+ self.state = None
42
+
43
+ def start(self, question: str):
44
+ self.state = ResearchState(question=question)
45
+
46
+ def ensure_started(self, question: str = ""):
47
+ if self.state is None:
48
+ self.start(question)
49
+
50
+ def reset(self):
51
+ self.state = None
52
+
53
+
54
+ research_context = ResearchContext()
55
+
56
+
57
+ # =========================================================
58
+ # Stateful Web Search
59
+ # =========================================================
60
+
61
+ class StatefulWebSearchTool(DuckDuckGoSearchTool):
62
+ """
63
+ Web search tool that also records discovered sources
64
+ in the current ResearchState.
65
+ """
66
+
67
+ name = "web_search"
68
+
69
+ description = (
70
+ "Searches the web for relevant sources. "
71
+ "Use this for source discovery. Search results are "
72
+ "leads and should normally be followed by visit_webpage "
73
+ "when factual evidence is needed."
74
+ )
75
+
76
+ def forward(self, query: str) -> str:
77
+ research_context.ensure_started()
78
+
79
+ results = super().forward(query)
80
+
81
+ # Store the search itself as research activity.
82
+ # The actual source evidence is recorded more precisely
83
+ # when visit_webpage reads the source.
84
+ return results
85
+
86
+
87
+ # =========================================================
88
+ # Stateful Webpage Reader
89
+ # =========================================================
90
+
91
+ class StatefulVisitWebpageTool(VisitWebpageTool):
92
+ """
93
+ Reads webpages and records the resulting source content
94
+ in ResearchState.
95
+ """
96
+
97
+ name = "visit_webpage"
98
+
99
+ description = (
100
+ "Visits a webpage and reads its contents. "
101
+ "Use this after web_search when you need actual "
102
+ "source evidence rather than only a search snippet."
103
+ )
104
+
105
+ def forward(self, url: str) -> str:
106
+ research_context.ensure_started()
107
+
108
+ content = super().forward(url)
109
+
110
+ # Record the source as evidence.
111
+ #
112
+ # At this stage we don't know which exact claim the
113
+ # source supports. The verification step can associate
114
+ # the collected sources with the claims supplied by
115
+ # the agent.
116
+ research_context.state.add_evidence(
117
+ claim="__SOURCE__",
118
+ source_url=url,
119
+ excerpt=content[:4000],
120
+ supports_claim=None,
121
+ )
122
+
123
+ return content
124
+
125
+
126
+ # =========================================================
127
+ # Verification Tool
128
+ # =========================================================
129
+
130
+ class VerifyResearchTool(Tool):
131
+ """
132
+ Runs the deterministic verification layer over the
133
+ current research state.
134
+ """
135
+
136
+ name = "verify_research"
137
+
138
+ description = (
139
+ "Verifies the claims in the current research session "
140
+ "against the sources that have been collected. "
141
+ "Use this before producing the final answer."
142
+ )
143
+
144
+ inputs = {
145
+ "claims": {
146
+ "type": "string",
147
+ "description": (
148
+ "The factual claims that need verification, "
149
+ "separated by newline."
150
+ ),
151
+ }
152
+ }
153
+
154
+ output_type = "string"
155
+
156
+ def forward(self, claims: str) -> str:
157
+ research_context.ensure_started()
158
+
159
+ state = research_context.state
160
+
161
+ # Normalize claims supplied by the agent.
162
+ claim_list = [
163
+ claim.strip()
164
+ for claim in claims.splitlines()
165
+ if claim.strip()
166
+ ]
167
+
168
+ # Register the claims.
169
+ for claim in claim_list:
170
+ state.add_claim(claim)
171
+
172
+ # Existing evidence was initially recorded against
173
+ # __SOURCE__. Associate the collected sources with
174
+ # the claims being verified.
175
+ #
176
+ # This is intentionally conservative: the verifier
177
+ # knows that these sources were collected, but the
178
+ # model still needs to determine whether they actually
179
+ # support or contradict each claim.
180
+ source_evidence = [
181
+ evidence
182
+ for evidence in state.evidence
183
+ if evidence.claim == "__SOURCE__"
184
+ ]
185
+
186
+ # Rebuild claim-level evidence.
187
+ #
188
+ # We do not automatically mark sources as supporting.
189
+ # They remain uncertain until the agent has inspected
190
+ # and reasoned about the evidence.
191
+ for claim in claim_list:
192
+ existing = state.evidence_for_claim(claim)
193
+
194
+ if not existing:
195
+ for source in source_evidence:
196
+ state.add_evidence(
197
+ claim=claim,
198
+ source_url=source.source_url,
199
+ excerpt=source.excerpt,
200
+ supports_claim=None,
201
+ )
202
+
203
+ verification = verify_research(state)
204
+
205
+ return _format_verification_result(verification)
206
+
207
+
208
+ def _format_verification_result(result: dict) -> str:
209
+ lines = []
210
+
211
+ lines.append("## Verification Results")
212
+ lines.append("")
213
+
214
+ for item in result["claims"]:
215
+ lines.append(
216
+ f"### {item['status']}: {item['claim']}"
217
+ )
218
+ lines.append(item["reason"])
219
+
220
+ if item["sources"]:
221
+ lines.append("Sources:")
222
+ for source in item["sources"]:
223
+ lines.append(f"- {source}")
224
+
225
+ lines.append("")
226
+
227
+ if result["verified"]:
228
+ lines.append("Overall result: SUPPORTED")
229
+ else:
230
+ lines.append(
231
+ "Overall result: NOT FULLY VERIFIED"
232
+ )
233
+
234
+ return "\n".join(lines)
235
+
236
+
237
+ # =========================================================
238
+ # Load Prompts
239
+ # =========================================================
240
 
241
  with open("prompts.yaml", "r", encoding="utf-8") as stream:
242
  prompt_templates = yaml.safe_load(stream)
243
 
244
 
245
+ # =========================================================
246
  # Tools
247
+ # =========================================================
248
 
249
+ web_search = StatefulWebSearchTool(
250
  max_results=10
251
  )
252
 
253
+ visit_webpage = StatefulVisitWebpageTool()
254
 
255
  calculator = Calculator()
256
 
257
+ verify_research = VerifyResearchTool()
258
 
259
+ final_answer = FinalAnswerTool()
260
 
261
  tools = [
262
  web_search,
263
  visit_webpage,
264
  calculator,
265
+ verify_research,
266
  final_answer,
267
  ]
268
 
269
 
270
+ # =========================================================
271
  # Model
272
+ # =========================================================
273
 
274
  model = HfApiModel(
275
  model_id=MODEL_ID,
 
279
  )
280
 
281
 
282
+ # =========================================================
283
+ # Agent
284
+ # =========================================================
285
 
286
  agent = CodeAgent(
287
  model=model,
 
292
  planning_interval=2,
293
  name="web_research_agent",
294
  description=(
295
+ "A web research and fact-verification agent that "
296
+ "searches for evidence, reads sources, performs "
297
+ "calculations, checks claims, detects uncertainty "
298
+ "and produces cited answers."
299
  ),
300
  prompt_templates=prompt_templates,
301
  )
302
 
303
 
304
+ # =========================================================
305
  # Launch
306
+ # =========================================================
307
 
308
  if __name__ == "__main__":
309
  GradioUI(agent).launch()