Build a Runnable Knowledge‑Base QA Skeleton with Deep Agents in 10 Days
This article walks through a lightweight, runnable knowledge‑base question‑answering skeleton built with Deep Agents, explains its current capabilities and limitations, shows the project structure and core code, and outlines a step‑by‑step upgrade path toward a production‑grade RAG system.
Conclusion
This skeleton is runnable, understandable, and extensible, but it is not a production‑grade Retrieval‑Augmented Generation (RAG) system.
Current capabilities:
Main Agent : created via create_deep_agent Knowledge Base : simulated with an in‑memory dictionary and keyword matching
CLI Interaction : allows asking questions and switching modes from the command line
Missing features (explicitly not implemented):
No real vector database integration
No Tavily or other web‑search tools
No embedding, rerank, or source citation pipeline
No checkpointer for cross‑turn persistence
Code‑review agent is only a placeholder and not dispatched
1. Project Structure
The repository layout:
deepagents-10days/</code>
<code>├── api/</code>
<code>│ ├── day1_intro.py</code>
<code>│ ├── day2_models.py</code>
<code>│ ├── day3_planning.py</code>
<code>│ ├── day4_filesystem.py</code>
<code>│ ├── day5_backends.py</code>
<code>│ ├── day6_sandbox.py</code>
<code>│ ├── day7_subagent.py</code>
<code>│ ├── day8_memory_permissions.py</code>
<code>│ ├── day9_skills_hitl.py</code>
<code>│ ├── day10_cli_acp.py</code>
<code>│ └── main.py</code>
<code>├── core/</code>
<code>│ ├── __init__.py</code>
<code>│ ├── config.py</code>
<code>│ └── coding_agent.py</code>
<code>├── tests/</code>
<code>│ └── test_article_accuracy.py</code>
<code>├── README.md</code>
<code>├── pyproject.toml</code>
<code>└── uv.lock api/holds daily example scripts and the final CLI entry point; core/ contains reusable configuration and the coding‑assistant wrapper; tests/ validates the article’s claims.
2. Creating the Main Agent
The core of api/main.py calls create_deep_agent with a system prompt that mentions web search and memory, but the example does not integrate a search tool nor persistent memory.
from deepagents import create_deep_agent
agent = create_deep_agent(
model="anthropic:claude-sonnet-4-6",
system_prompt="""You are a knowledge‑base QA assistant.
Capabilities:
- Answer questions about technical documentation
- Can search the web for up‑to‑date information
- Remembers conversation history
If you do not know the answer, say you do not know.""",
)3. Knowledge‑Base Simulation
A simple KnowledgeBase class stores documents in a dictionary and performs keyword matching:
class KnowledgeBase:
def __init__(self):
self.docs = {}
self.doc_count = 0
def add_document(self, name: str, content: str):
self.docs[name] = content
self.doc_count += 1
return f"Added document: {name}"
def search(self, query: str) -> list:
results = []
for name, content in self.docs.items():
if any(kw in content for kw in query.split()):
results.append(f"[{name}]: {content[:100]}...")
return results if results else []This implementation is suitable for teaching because it has few dependencies and clearly shows how retrieved snippets are inserted into prompts, but it does not represent a production RAG system.
Suggested production upgrades (current → production):
In‑memory dictionary → Chroma / FAISS / Milvus / pgvector
Keyword matching → embedding‑based retrieval
No metadata → add document source, permissions, timestamps
No rerank → introduce a reranking step for candidate passages
No citations → include source references in answers
The author recommends first getting the simple retrieval working, then swapping in a vector store.
4. What the chat() Function Does
The workflow consists of four steps:
Call rag_search() to query the local simulated knowledge base.
If context is found, concatenate it with the user query.
Invoke the agent with the combined message.
Return the content of the last message from the agent’s response.
def chat(user_input: str, thread_id: str = "default") -> str:
context = rag_search(user_input)
if context:
message = f"{user_input}
{context}"
else:
message = user_input
result = agent.invoke({"messages": [{"role": "user", "content": message}]})
messages = result.get("messages") or []
if messages:
last_msg = messages[-1]
return getattr(last_msg, "content", None) or "Sorry, I couldn't find relevant information."
return "Sorry, processing failed."Two boundaries are highlighted: thread_id is currently unused; passing it to
agent.invoke(config={"configurable": {"thread_id": thread_id}})and configuring a checkpointer would enable true multi‑turn state restoration.
No checkpointer is configured, so the function should not be interpreted as a fully persistent dialogue system.
5. Code‑Review Agent Placeholder
A second agent is created for code review:
code_agent = create_deep_agent(
model="anthropic:claude-sonnet-4-6",
system_prompt="""You are a code review assistant.""",
)The CLI branch !code currently only prints a placeholder message and does not invoke code_agent. The code demonstrates that a main agent and a sub‑agent can coexist; integration of the sub‑agent is left for future work.
6. How to Run the Skeleton
cd deepagents-10days
uv sync
export ANTHROPIC_API_KEY=sk-ant-...
uv run python api/main.pyOn startup, three example documents are loaded:
LangGraph intro : demonstrates framework knowledge Q&A
LangChain intro : demonstrates ecosystem concept Q&A
Deep Agents intro : demonstrates series‑specific Q&A
CLI commands:
!code # switch to code‑review mode
!normal # return to normal QA mode
!help # show commands
exit # quit programThis verifies the main flow: input question → retrieve context → invoke agent → output answer.
7. Mapping to the 10‑Day Curriculum
Day 1 – create_deep_agent: used
Day 2 – Model configuration: string model used
Day 3 – write_todos: agent can invoke automatically in complex tasks
Day 4 – Filesystem: backend not explicitly connected
Day 5 – Backend: state/filesystem/store can be swapped later
Day 6 – Execute: not enabled
Day 7 – Sub‑agent: code‑assistant placeholder, not dispatched
Day 8 – Memory / Permissions: not configured
Day 9 – Skills / HITL: not configured
Day 10 – CLI / API: local CLI skeleton
8. Upgrade Roadmap
Prioritized steps to turn the skeleton into an enterprise knowledge‑base:
Replace keyword retrieval with vector retrieval – improves answer quality immediately.
Add source citations to answers – reduces hallucinations and aids auditability.
Integrate a checkpointer – supports multi‑turn state restoration.
Connect subagents – distributes responsibilities among retrieval, code review, and summarization.
Add memory and permissions – remembers rules and enforces document boundaries.
Attach sandbox + HITL to execute – makes verification loops controllable.
Expose as an API service – enables integration with front‑ends, enterprise chat tools, or internal platforms.
This incremental approach ensures each change can be validated before proceeding, avoiding the pitfall of trying to build a full RAG system, agent orchestration, backend services, UI, and permission layers all at once.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Tech Ocean
Focused on AI programming, sharing ready-to-use development efficiency solutions.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
