add main.py

This commit is contained in:
2026-05-28 07:33:18 +00:00
parent c43bbd68d2
commit d10fdc4e71
+109 -139
View File
@@ -1,163 +1,133 @@
""" """
Main script for AI Fluency Plan. Main entry point for the LangChain + Qdrant knowledgebase agent.
This script generates a personal AI fluency plan based on the course structure and learning objectives. The script demonstrates three independent usage examples:
It prints the plan to stdout. The plan is deterministic and does not depend on external services.
The script contains: 1. **Simple search** a single query is sent to the ``search_knowledge_base`` tool.
- A `Plan` dataclass with sections and items. 2. **Add & search** a document is added to the collection and then searched.
- A function `generate_plan()` that builds the plan. 3. **Interactive chat** an agent that can call both tools in a conversational
- A `main()` entry point that prints the plan in a readable format. setting, using stream mode so that responses appear tokenbytoken.
The implementation follows the requirements: All examples are wrapped in ``if __name__ == "__main__"`` blocks so they run
- At least 80 lines of code. only when the module is executed directly.
- No external dependencies beyond the standard library.
- Clear docstrings and type hints.
""" """
from __future__ import annotations from __future__ import annotations
import textwrap import os
from dataclasses import dataclass, field from typing import Dict, Any
from typing import List
@dataclass # ---------------------------------------------------------------------------
class PlanItem: # LangChain imports we use only what is required for the examples.
"""Represents a single item in a plan section.""" # ---------------------------------------------------------------------------
title: str
description: str
resources: List[str] = field(default_factory=list)
def __str__(self) -> str: from langchain_openai import ChatOpenAI
res = f"- {self.title}: {self.description}" from langchain_core.messages import HumanMessage
if self.resources: from langchain.agents import create_agent
res += "\n Resources:\n" from langchain.tools import tool
for r in self.resources:
res += f" * {r}\n"
return res.rstrip()
@dataclass # Import our custom tools
class PlanSection: from .tools import search_knowledge_base, add_to_knowledge_base
"""A section of the overall plan."""
name: str
items: List[PlanItem] = field(default_factory=list)
def __str__(self) -> str: # ---------------------------------------------------------------------------
header = f"\n=== {self.name} ===\n" # LLM configuration the same model is used for all examples.
body = "\n".join(str(item) for item in self.items) # ---------------------------------------------------------------------------
return header + body
@dataclass llm = ChatOpenAI(
class Plan: model="openai/gpt-oss-20b:free",
"""Full plan consisting of multiple sections.""" base_url="https://platform.brojs.ru/jrnl-bh/api/inference/v1",
title: str api_key=os.getenv("JOURNAL_MCP_PAT"),
sections: List[PlanSection] = field(default_factory=list) temperature=0.5,
)
def __str__(self) -> str: # ---------------------------------------------------------------------------
header = f"\n# {self.title}\n" # Helper format a LangChain message for printing.
body = "\n".join(str(section) for section in self.sections) # ---------------------------------------------------------------------------
return header + body
def generate_plan() -> Plan: def _format_message(msg: Any) -> str:
"""Builds a deterministic AI fluency plan. if hasattr(msg, "content") and msg.content:
return msg.content
# Fallback to tool call representation
if hasattr(msg, "tool_calls") and msg.tool_calls:
tc = msg.tool_calls[0]
return f"{tc['name']}({tc['args']})"
return str(msg)
The plan is based on the course structure described in the assignment. # ---------------------------------------------------------------------------
It covers foundational knowledge, handson projects, advanced topics, # Example 1 simple search using the tool directly.
reflection and documentation. Each section contains concrete items with # ---------------------------------------------------------------------------
short descriptions and optional resource links.
""" def example_simple_search() -> None:
foundation = PlanSection( print("\n=== Example 1: Simple Search ===")
name="Foundational Knowledge (Weeks 12)", query = "Python async programming"
items=[ result = search_knowledge_base(query, max_results=3)
PlanItem( print(f"Query: {query}\nResult:\n{result}")
title="Study the AI Fluency Framework Foundations",
description=( # ---------------------------------------------------------------------------
"Read the provided material and summarize key concepts such as " # Example 2 add a document then search.
"model architecture, tokenization, inference pipelines, and " # ---------------------------------------------------------------------------
"ethical considerations."
), def example_add_and_search() -> None:
resources=["https://anthropic.skilljar.com/ai-fluency-framework-foundations"], print("\n=== Example 2: Add & Search ===")
), content = (
PlanItem( "Async programming in Python is supported via the asyncio library. "
title="Complete all modules on understanding AI concepts", "It allows concurrent execution of IObound tasks without threads."
description="Work through interactive lessons and quizzes to reinforce learning.", )
), title = "Python Asyncio"
], add_msg = add_to_knowledge_base(content, title=title)
print(add_msg)
# Now search for a related term.
query = "asyncio" # short keyword to trigger the newly added doc
result = search_knowledge_base(query, max_results=2)
print(f"Search results for '{query}':\n{result}")
# ---------------------------------------------------------------------------
# Example 3 interactive chat agent using stream mode.
# ---------------------------------------------------------------------------
def example_chat_agent() -> None:
print("\n=== Example 3: Interactive Chat Agent (stream) ===")
# Create an agent that can call our two tools.
agent = create_agent(
llm=llm,
tools=[search_knowledge_base, add_to_knowledge_base],
system_prompt="You are a helpful assistant with access to a knowledge base. "
"Use the provided tools to answer user queries.",
) )
hands_on = PlanSection( # Simple chat loop only one turn for demonstration.
name="Handson Projects (Weeks 35)", user_input = "Tell me about async programming in Python."
items=[ print(f"User: {user_input}\n")
PlanItem(
title="Build a simple chatbot using LangChain in stream mode", stream = agent.stream(
description=( {"messages": [HumanMessage(content=user_input)]},
"Implement a Python script that streams responses from an LLM, " stream_mode=["messages", "updates"],
"demonstrating tokenbytoken output."
),
),
PlanItem(
title="Deploy the chatbot locally and test with real user inputs",
description="Run the script in a terminal session and observe streaming.",
),
],
) )
advanced = PlanSection( step = 1
name="Advanced Topics (Weeks 67)", for chunk_type, chunk_data in stream:
items=[ if chunk_type == "messages":
PlanItem( msg, _meta = chunk_data
title="Explore LangGraph for stateful conversational agents", # Detect step change a simple visual separator.
description=( if _meta.get("langgraph_step") != step:
"Create a small graph that uses interrupt and resume to involve the user in decision making." step = _meta["langgraph_step"]
), print("\n--- --- --- \n")
), print(_format_message(msg), end="", flush=True)
PlanItem( elif chunk_type == "updates":
title="Implement a retrieval system using Qdrant", # When the model finishes a tool call we can show it.
description=( if chunk_data.get("model"):
"Set up an inmemory Qdrant collection, embed documents with Ollama embeddings, " last_msg = chunk_data["model"]["messages"][-1]
"and integrate semantic search into the chatbot." print(_format_message(last_msg))
),
),
],
)
reflection = PlanSection( print("\n--- End of conversation ---")
name="Reflection & Documentation (Week 8)",
items=[
PlanItem(
title="Write a onepage reflection on what was learned",
description=(
"Discuss challenges faced, insights gained, and next steps for deeper learning."
),
),
PlanItem(
title="Prepare a short demo video (5min) showcasing the chatbot and retrieval system",
description="Record screen capture and narrate key features.",
),
],
)
final = PlanSection( # ---------------------------------------------------------------------------
name="Final Deliverable (Week 9)", # Entry point run all examples.
items=[ # ---------------------------------------------------------------------------
PlanItem(
title="Submit the plan, code repository link, and demo video",
description=(
"Ensure all code is wellcommented, includes a README, and passes linting."
),
),
],
)
return Plan(
title="AI Fluency Personal Plan", sections=[foundation, hands_on, advanced, reflection, final]
)
def main() -> None:
"""Entry point that prints the generated plan."""
plan = generate_plan()
print(str(plan))
if __name__ == "__main__": if __name__ == "__main__":
main() example_simple_search()
example_add_and_search()
example_chat_agent()