1"""š¤ DeepKnowledge - An AI Agent that iteratively searches a knowledge base to answer questions
2
3This agent performs iterative searches through its knowledge base, breaking down complex
4queries into sub-questions, and synthesizing comprehensive answers. It's designed to explore
5topics deeply and thoroughly by following chains of reasoning.
6
7In this example, the agent uses the Kern documentation as a knowledge base
8
9Key Features:
10- Iteratively searches a knowledge base
11- Source attribution and citations
12"""
13
14from textwrap import dedent
15from typing import List, Optional
16
17import inquirer
18import typer
19from kern.agent import Agent
20from kern.db.sqlite import SqliteDb
21from kern.knowledge.embedder.openai import OpenAIEmbedder
22from kern.knowledge.knowledge import Knowledge
23from kern.models.groq import Groq
24from kern.vectordb.lancedb import LanceDb, SearchType
25from rich import print
26
27def initialize_knowledge_base():
28 """Initialize the knowledge base with your preferred documentation or knowledge source
29 Here we use Kern docs as an example, but you can replace with any relevant URLs
30 """
31 agent_knowledge = Knowledge(
32 vector_db=LanceDb(
33 uri="tmp/lancedb",
34 table_name="deep_knowledge_knowledge",
35 search_type=SearchType.hybrid,
36 embedder=OpenAIEmbedder(id="text-embedding-3-small"),
37 ),
38 )
39 agent_knowledge.insert(url="https://kern.ndx.rocks/llms-full.txt")
40 return agent_knowledge
41
42def get_db():
43 return SqliteDb(db_file="tmp/agents.db")
44
45def create_agent(session_id: Optional[str] = None) -> Agent:
46 """Create and return a configured DeepKnowledge agent."""
47 agent_knowledge = initialize_knowledge_base()
48 db = get_db()
49 return Agent(
50 name="DeepKnowledge",
51 session_id=session_id,
52 model=Groq(id="llama-3.3-70b-versatile"),
53 description=dedent("""\
54 You are DeepKnowledge, an advanced reasoning agent designed to provide thorough,
55 well-researched answers to any query by searching your knowledge base.
56
57 Your strengths include:
58 - Breaking down complex topics into manageable components
59 - Connecting information across multiple domains
60 - Providing nuanced, well-researched answers
61 - Maintaining intellectual honesty and citing sources
62 - Explaining complex concepts in clear, accessible terms"""),
63 instructions=dedent("""\
64 Your mission is to leave no stone unturned in your pursuit of the correct answer.
65
66 To achieve this, follow these steps:
67 1. **Analyze the input and break it down into key components**.
68 2. **Search terms**: You must identify at least 3-5 key search terms to search for.
69 3. **Initial Search:** Searching your knowledge base for relevant information. You must make atleast 3 searches to get all relevant information.
70 4. **Evaluation:** If the answer from the knowledge base is incomplete, ambiguous, or insufficient - Ask the user for clarification. Do not make informed guesses.
71 5. **Iterative Process:**
72 - Continue searching your knowledge base till you have a comprehensive answer.
73 - Reevaluate the completeness of your answer after each search iteration.
74 - Repeat the search process until you are confident that every aspect of the question is addressed.
75 4. **Reasoning Documentation:** Clearly document your reasoning process:
76 - Note when additional searches were triggered.
77 - Indicate which pieces of information came from the knowledge base and where it was sourced from.
78 - Explain how you reconciled any conflicting or ambiguous information.
79 5. **Final Synthesis:** Only finalize and present your answer once you have verified it through multiple search passes.
80 Include all pertinent details and provide proper references.
81 6. **Continuous Improvement:** If new, relevant information emerges even after presenting your answer,
82 be prepared to update or expand upon your response.
83
84 **Communication Style:**
85 - Use clear and concise language.
86 - Organize your response with numbered steps, bullet points, or short paragraphs as needed.
87 - Be transparent about your search process and cite your sources.
88 - Ensure that your final answer is comprehensive and leaves no part of the query unaddressed.
89
90 Remember: **Do not finalize your answer until every angle of the question has been explored.**"""),
91 additional_context=dedent("""\
92 You should only respond with the final answer and the reasoning process.
93 No need to include irrelevant information.
94
95 - User ID: {user_id}
96 - Memory: You have access to your previous search results and reasoning process.
97 """),
98 knowledge=agent_knowledge,
99 db=db,
100 add_history_to_context=True,
101 num_history_runs=3,
102 read_chat_history=True,
103 markdown=True,
104 )
105
106def get_example_topics() -> List[str]:
107 """Return a list of example topics for the agent."""
108 return [
109 "What are AI agents and how do they work in Kern?",
110 "What chunking strategies does Kern support for text processing?",
111 "How can I implement custom tools in Kern?",
112 "How does knowledge retrieval work in Kern?",
113 "What types of embeddings does Kern support?",
114 ]
115
116def handle_session_selection() -> Optional[str]:
117 """Handle session selection and return the selected session ID."""
118 db = get_db()
119
120 new = typer.confirm("Do you want to start a new session?", default=True)
121 if new:
122 return None
123
124 existing_sessions = db.get_sessions()
125 if not existing_sessions:
126 print("No existing sessions found. Starting a new session.")
127 return None
128
129 print("\nExisting sessions:")
130 for i, session in enumerate(existing_sessions, 1):
131 print(f"{i}. {session.session_id}") # type: ignore
132
133 session_idx = typer.prompt(
134 "Choose a session number to continue (or press Enter for most recent)",
135 default=1,
136 )
137
138 try:
139 return existing_sessions[int(session_idx) - 1].session_id # type: ignore
140 except (ValueError, IndexError):
141 return existing_sessions[0].session_id # type: ignore
142
143def run_interactive_loop(agent: Agent):
144 """Run the interactive question-answering loop."""
145 example_topics = get_example_topics()
146
147 while True:
148 choices = [f"{i + 1}. {topic}" for i, topic in enumerate(example_topics)]
149 choices.extend(["Enter custom question...", "Exit"])
150
151 questions = [
152 inquirer.List(
153 "topic",
154 message="Select a topic or ask a different question:",
155 choices=choices,
156 )
157 ]
158 answer = inquirer.prompt(questions)
159
160 if answer and answer["topic"] == "Exit":
161 break
162
163 if answer and answer["topic"] == "Enter custom question...":
164 questions = [inquirer.Text("custom", message="Enter your question:")]
165 custom_answer = inquirer.prompt(questions)
166 topic = custom_answer["custom"] # type: ignore
167 else:
168 topic = example_topics[int(answer["topic"].split(".")[0]) - 1] # type: ignore
169
170 agent.print_response(topic, stream=True)
171
172def deep_knowledge_agent():
173 """Main function to run the DeepKnowledge agent."""
174
175 session_id = handle_session_selection()
176 agent = create_agent(session_id)
177
178 print("\nš¤ Welcome to DeepKnowledge - Your Advanced Research Assistant! š")
179 if session_id is None:
180 session_id = agent.session_id
181 if session_id is not None:
182 print(f"[bold green]Started New Session: {session_id}[/bold green]\n")
183 else:
184 print("[bold green]Started New Session[/bold green]\n")
185 else:
186 print(f"[bold blue]Continuing Previous Session: {session_id}[/bold blue]\n")
187
188 run_interactive_loop(agent)
189
190if __name__ == "__main__":
191 typer.run(deep_knowledge_agent)