Files
task-6a1d75dbfd30e81cf3126b09/main.py
T
2026-06-15 12:14:04 +00:00

129 lines
4.3 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import os
import asyncio
from typing import TypedDict, Annotated, List
from langchain_openai import ChatOpenAI
from langchain_core.messages import HumanMessage
from langchain.tools import tool
from langchain_tavily import TavilySearchResults
from langgraph.graph import StateGraph, START, END
from langgraph.graph.message import add_messages
from deepagents import create_deep_agent
from deepagents.backends import FilesystemBackend, LocalShellBackend, CompositeBackend
# ----------------- LLM -----------------
llm = ChatOpenAI(
model="openai/gpt-oss-20b:free",
base_url="https://openrouter.ai/api/v1",
api_key=os.getenv("OPENAI_API_KEY"),
temperature=0.0,
)
# ----------------- Backend -----------------
backend = CompositeBackend([
LocalShellBackend(workspace_dir="./workspace"),
FilesystemBackend(),
])
# ----------------- Tavily Tool -----------------
search_tool = TavilySearchResults(max_results=3)
# ----------------- State -----------------
class BriefState(TypedDict):
topic: str
outline: List[str] | None
step_index: int
notes: List[str]
final_brief: str | None
# ----------------- Nodes -----------------
async def outline_node(state: BriefState) -> BriefState:
prompt = f"""Create a concise outline of 45 research steps for the topic: {state['topic']}. Return a JSON array of strings."""
response = await llm.ainvoke([HumanMessage(content=prompt)])
# Parse JSON array
import json
try:
outline = json.loads(response.content)
if not isinstance(outline, list):
raise ValueError
except Exception:
outline = ["Step 1: Define scope", "Step 2: Search", "Step 3: Analyze", "Step 4: Summarize"]
state.update(outline=outline, step_index=0, notes=[], final_brief=None)
return state
async def research_step_node(state: BriefState) -> BriefState:
step = state['outline'][state['step_index']]
# Perform web search via Tavily
results = await search_tool.ainvoke(step)
# Summarize results into 58 sentences
summary_prompt = f"""Summarize the following search results into 58 concise sentences for the research step: {step}.
Results:
{results}"""
summary = await llm.ainvoke([HumanMessage(content=summary_prompt)])
state['notes'].append(f"{step}\n{summary.content}")
state['step_index'] += 1
return state
async def synthesize_node(state: BriefState) -> BriefState:
# Combine notes into a coherent brief with headings
heading_prompt = """Combine the following notes into a ½–1 page research brief. Use the step titles as headings and write in a clear, academic style.
Notes:
""" + "\n\n".join(state['notes'])
brief = await llm.ainvoke([HumanMessage(content=heading_prompt)])
state['final_brief'] = brief.content
return state
# ----------------- Graph -----------------
graph = StateGraph(BriefState)
graph.add_node("outline", outline_node)
graph.add_node("research_step", research_step_node)
graph.add_node("synthesize", synthesize_node)
# Entry point
graph.set_entry_point("outline")
# Conditional edges
graph.add_conditional_edges(
"outline",
lambda _: "research_step",
)
graph.add_conditional_edges(
"research_step",
lambda state: "synthesize" if state['step_index'] >= len(state['outline']) else "research_step",
)
graph.add_edge("synthesize", END)
app = graph.compile()
# ----------------- DeepAgent -----------------
agent = create_deep_agent(
model=llm,
tools=[search_tool],
backend=backend,
system_prompt="You are a research assistant that builds a brief based on a topic.",
)
# ----------------- Main -----------------
async def main():
topic = os.getenv("DEFAULT_TOPIC", "Как студенту безопасно подключать MCP к LangChain")
# Run graph to get outline and notes
state = await app.ainvoke({"topic": topic, "outline": None, "step_index": 0, "notes": [], "final_brief": None})
# Print outline
print("\n=== Outline ===")
for i, step in enumerate(state['outline'], 1):
print(f"{i}. {step}")
# Print each research step note
for i, note in enumerate(state['notes'], 1):
print(f"\n[Step {i}] {note.splitlines()[0]}")
print(note.splitlines()[1])
# Print final brief
print("\n=== Final Brief ===")
print(state['final_brief'])
if __name__ == "__main__":
asyncio.run(main())