With Deep Agents we get a relatively new component from LangChain/LangGraph that allows us to build high-level agents. Let us see how they fit into the big picture and how we can use them in our own applications.
Where do Deep Agents fit into LangGraph/LangChain?
deepagents is a standalone library built on top of LangChain’s core building blocks for agents. It uses the LangGraph runtime for durable execution, streaming, human-in-the-loop, and other features. (from docs.langchain.com)
With Deep Agents we get an “agent harness” and not just a low-level library to build our own solutions. We can get a pre-configured system with the name Deep Agents Code that behaves like Claude Code, or we wire up our tools to build a custom agent where we do not need to build a workflow as we usually do in LangGraph.
Installation
To use this new feature, we need to install the deepagents package:
uvpipinstalldeepagentslangchain-openai
Rebuild the multi-agents debate tool with Deep Agents
In Python Friday #338 we used multi-agents to debate the merit of an idea with an optimist and a pessimist before we created a summary and gave advice on how to proceed. We can take this idea and rebuild it with Deep Agents to see how those two approaches differ.
As with multi-agents, we start with a few imports and the configuration of our LLM:
importsysimportwarningsfromtypingimportAnyfromlangchain_openaiimportChatOpenAIwarnings.filterwarnings("ignore",message=".*allowed_objects.*")fromdeepagentsimportcreate_deep_agentsys.stdout.reconfigure(encoding="utf-8")# Same LM Studio initialization as the original script.llm=ChatOpenAI(base_url="http://localhost:1234/v1",api_key="lm-studio",model="openai/gpt-oss-20b",temperature=0.1,)
For the pessimist and optimist, we need prompts and a structure to hold our subagents:
OPTIMIST_SYSTEM=("You are an extreme optimist in a structured debate. Argue the maximum ""upside, growth, and opportunity of the topic. When earlier pessimistic ""points are included in the task, rebut them directly. Return EXACTLY ""3 short points, one per line, with no numbering and no preamble.")PESSIMIST_SYSTEM=("You are an extreme pessimist in a structured debate. Argue the severe ""risks, hidden costs, and technical bottlenecks of the topic. When earlier ""optimistic points are included in the task, rebut them directly. Return ""EXACTLY 3 short points, one per line, with no numbering and no preamble.")COORDINATOR_SYSTEM="""You run a four-turn optimist-versus-pessimist debate.You MUST use the task tool exactly four times and in this order:1. Call the optimist with the topic and ask for its initial 3 points.2. Call the pessimist with the topic plus the optimist's exact points, asking for 3 risks or rebuttals.3. Call the optimist again with the complete debate so far, asking for 3 rebuttals or additional opportunities.4. Call the pessimist again with the complete debate so far, asking for 3 rebuttals or additional risks.Do not skip a turn. Pass previous points into every later task so each speakercan respond to what is already on the table.After all four task calls, act as a neutral judge. Return EXACTLY 5 lines,with no numbering, headings, markdown fences, or preamble:Lines 1-2: the two strongest opportunities, each beginning with [+]Lines 3-4: the two most serious risks, each beginning with [-]Line 5: begin with [>] and state either:- PROCEED, followed by a one-clause reason, or- REVISIT, followed by a one-clause reason explaining why the risks should be addressed first.Judge importance rather than simply counting claims. Do not mention agents,delegation, task calls, or the debate process in the final five lines."""subagents=[{"name":"optimist","description":("Produces exactly three concise opportunities or optimistic ""rebuttals for an idea. Use for turns 1 and 3."),"system_prompt":OPTIMIST_SYSTEM,"model":llm,},{"name":"pessimist","description":("Produces exactly three concise risks or pessimistic rebuttals ""for an idea. Use for turns 2 and 4."),"system_prompt":PESSIMIST_SYSTEM,"model":llm,},]
With a few helper methods we can get a robust output that works even when the LLM may trip and produces output that does not exactly match our requirements:
defmessage_text(message:Any)->str:"""Extract plain text from a LangChain message."""content=getattr(message,"content",message)ifisinstance(content,str):returncontent.strip()ifisinstance(content,list):parts:list[str]=[]foritemincontent:ifisinstance(item,str):parts.append(item)elifisinstance(item,dict)anditem.get("type")=="text":parts.append(str(item.get("text","")))return"\n".join(partforpartinpartsifpart).strip()returnstr(content).strip()defis_valid_summary(text:str)->bool:"""Check the same five-line conclusion contract as the old script."""lines=[line.strip()forlineintext.splitlines()ifline.strip()]return(len(lines)==5andall(line.startswith("[+]")forlineinlines[:2])andall(line.startswith("[-]")forlineinlines[2:4])andlines[4].startswith("[>]")and("PROCEED"inlines[4]or"REVISIT"inlines[4]))defrepair_summary(text:str,topic:str)->str:"""Use the same local LLM to enforce the output format if needed."""response=llm.invoke([("system","Reformat the supplied conclusion into EXACTLY 5 non-empty ""lines, with no numbering or preamble. Lines 1-2 must begin ""with [+] and contain the two strongest opportunities. Lines ""3-4 must begin with [-] and contain the two most serious ""risks. Line 5 must begin with [>] and contain either PROCEED ""or REVISIT plus a one-clause reason. Preserve the meaning and ""do not add unsupported claims.",),("user",f"Topic: {topic}\n\nConclusion to reformat:\n{text}",),])returnmessage_text(response)defrun_debate(topic:str)->str:result=debate_agent.invoke({"messages":[{"role":"user","content":(f"Debate this topic and produce the required final "f"five-line conclusion:\n\n{topic}"),}]},{"recursion_limit":40},)summary=message_text(result["messages"][-1])ifnotis_valid_summary(summary):summary=repair_summary(summary,topic)returnsummary
As the final step, we glue everything together in a main() function:
defmain()->None:topic=sys.argv[1]iflen(sys.argv)>1else("Migrating a legacy monolith to a fully decentralized ""AI-agent architecture.")png_bytes=debate_agent.get_graph(xray=1).draw_mermaid_png()withopen("multi_agent_debate.png","wb")asfile:file.write(png_bytes)print(f"--- DEBATE --- {topic}")summary=run_debate(topic)print("\n\n--- SUMMARY ---")print(summary)print("--- /SUMMARY ---")if__name__=="__main__":main()
We can use our debate_agent and grab the LangGraph graph and visualise it as we did in all other LangGraph applications:
This gives us a generic workflow that is the blueprint for all Deep Agents.
Run the agent
If we run the agent, we see the main difference to our multi-agent approach: We do not get an intermediate output and need to wait until we have a summary:
--- DEBATE ---
Migrating a legacy monolith to a fully decentralized AI-agent architecture.
--- SUMMARY ---
[+] Unlock micro‑service scalability by letting each agent run in its own
container or serverless function, instantly handling spikes without
monolith bottlenecks.
[+] Enable continuous learning: agents can pull the latest models from a
shared registry and update locally, so new AI capabilities roll out to
all users with zero downtime.
[-] Security becomes a nightmare: each agent exposes an interface; patching
vulnerabilities across dozens of containers multiplies attack surface
and audit complexity.
[-] Operational overhead skyrockets: orchestrating model updates, monitoring
inter‑agent health, and ensuring reliable message passing demands tooling
that most teams lack, turning the promised agility into costly maintenance.
[>] PROCEED, because the scalability and market opportunities outweigh the
identified risks when mitigated with robust data protection and compliance
planning.
We give up control over the different steps but gain flexibility by not needing to define any workflow on our own. We can build complex agents by focusing on the tools and subagents and do not need to think how to connect the nodes.
Next
With this basic introduction to Deep Agents, we get a first glimpse on this new approach. We can focus on the tasks we want to do and not bother with the workflow. Next week we add another example where we use Frontmatter and the file system to tag blog posts.