A newer version of the Streamlit SDK is available:
1.54.0
SPARKNET: Technical Report
AI-Powered Multi-Agent System for Research Valorization
Table of Contents
- Executive Summary
- Introduction
- System Architecture
- Theoretical Foundations
- Core Components
- Workflow Engine
- Implementation Details
- Use Case: Patent Wake-Up
- Performance Considerations
- Conclusion
1. Executive Summary
SPARKNET is an autonomous multi-agent AI system designed for research valorization and technology transfer. Built on modern agentic AI principles, it leverages LangGraph for workflow orchestration, LangChain for LLM integration, and ChromaDB for vector-based memory. The system transforms dormant intellectual property into commercialization opportunities throughs a coordinated pipeline of specialized agents.
Key Capabilities:
- Multi-agent orchestration with cyclic refinement
- Local LLM deployment via Ollama (privacy-preserving)
- Vector-based episodic and semantic memory
- Automated patent analysis and Technology Readiness Level (TRL) assessment
- Market opportunity identification and stakeholder matching
- Professional valorization brief generation
2. Introduction
2.1 Problem Statement
University technology transfer offices face significant challenges:
- Volume: Thousands of patents remain dormant in institutional portfolios
- Complexity: Manual analysis requires deep domain expertise
- Time: Traditional evaluation takes days to weeks per patent
- Resources: Limited staff cannot process the backlog efficiently
2.2 Solution Approach
SPARKNET addresses these challenges through an agentic AI architecture that:
- Automates document analysis and information extraction
- Applies domain expertise through specialized agents
- Provides structured, actionable outputs
- Learns from past experiences to improve future performance
2.3 Design Principles
| Principle | Implementation |
|---|---|
| Autonomy | Agents operate independently with defined goals |
| Specialization | Each agent focuses on specific tasks |
| Collaboration | Agents share information through structured state |
| Iteration | Quality-driven refinement cycles |
| Memory | Vector stores for contextual learning |
| Privacy | Local LLM deployment via Ollama |
3. System Architecture
3.1 High-Level Architecture
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β SPARKNET SYSTEM β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β β
β βββββββββββββββ βββββββββββββββ βββββββββββββββββββββββββββ β
β β Frontend β β Backend β β LLM Layer β β
β β Next.js βββββΊβ FastAPI βββββΊβ Ollama (4 Models) β β
β β Port 3000 β β Port 8000 β β - llama3.1:8b β β
β βββββββββββββββ ββββββββ¬βββββββ β - mistral:latest β β
β β β - qwen2.5:14b β β
β βΌ β - gemma2:2b β β
β ββββββββββββββββββ βββββββββββββββββββββββββββ β
β β LangGraph β β
β β Workflow βββββΊ ChromaDB (Vector Store) β
β β (StateGraph) β β
β βββββββββ¬βββββββββ β
β β β
β ββββββββββββββββββββΌβββββββββββββββββββ β
β βΌ βΌ βΌ β
β βββββββββββββ βββββββββββββββ βββββββββββββ β
β β Planner β β Executor β β Critic β β
β β Agent β β Agents β β Agent β β
β βββββββββββββ βββββββββββββββ βββββββββββββ β
β β
β βββββββββββββ βββββββββββββββ βββββββββββββ β
β β Memory β β VisionOCR β β Tools β β
β β Agent β β Agent β β Registry β β
β βββββββββββββ βββββββββββββββ βββββββββββββ β
β β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
3.2 Layer Description
| Layer | Technology | Purpose |
|---|---|---|
| Presentation | Next.js, React, TypeScript | User interface, file upload, results display |
| API | FastAPI, Python 3.10+ | RESTful endpoints, async processing |
| Orchestration | LangGraph (StateGraph) | Workflow execution, conditional routing |
| Agent | LangChain, Custom Agents | Task-specific processing |
| LLM | Ollama (Local) | Natural language understanding and generation |
| Memory | ChromaDB | Vector storage, semantic search |
4. Theoretical Foundations
4.1 Agentic AI Paradigm
SPARKNET implements the modern agentic AI paradigm characterized by:
4.1.1 Agent Definition
An agent in SPARKNET is defined as a tuple:
Agent = (S, A, T, R, Ο)
Where:
- S = State space (AgentState in LangGraph)
- A = Action space (tool calls, LLM invocations)
- T = Transition function (workflow edges)
- R = Reward signal (validation score)
- Ο = Policy (LLM-based decision making)
4.1.2 Multi-Agent Coordination
The system employs hierarchical coordination:
Coordinator (Workflow)
β
βββββββββββββββββββΌββββββββββββββββββ
βΌ βΌ βΌ
Planner Executors Critic
(Strategic) (Tactical) (Evaluative)
β β β
ββββββββββββββββββ΄ββββββββββββββββββ
βΌ
Shared State (AgentState)
4.2 State Machine Formalism
The LangGraph workflow is formally a Finite State Machine with Memory:
FSM-M = (Q, Ξ£, Ξ΄, qβ, F, M)
Where:
- Q = {PLANNER, ROUTER, EXECUTOR, CRITIC, REFINE, FINISH}
- Ξ£ = Input alphabet (task descriptions, documents)
- Ξ΄ = Transition function (conditional edges)
- qβ = PLANNER (initial state)
- F = {FINISH} (accepting states)
- M = AgentState (memory/context)
4.3 Quality-Driven Refinement
The system implements a feedback control loop:
βββββββββββββββββββββββββββββββ
β β
βΌ β
Input β PLAN β EXECUTE β VALIDATE ββYESβββ OUTPUT
β
NO (score < threshold)
β
βΌ
REFINE
β
βββββββββββββββββββ (back to PLAN)
Convergence Condition:
terminate iff (validation_score β₯ quality_threshold) OR (iterations β₯ max_iterations)
4.4 Vector Memory Architecture
The memory system uses dense vector embeddings for semantic retrieval:
Memory Types:
βββ Episodic Memory β Past workflow executions, outcomes
βββ Semantic Memory β Domain knowledge, legal frameworks
βββ Stakeholder Memory β Partner profiles, capabilities
Retrieval Function:
retrieve(query, top_k) = argmax_k(cosine_similarity(embed(query), embed(documents)))
5. Core Components
5.1 BaseAgent Abstract Class
All agents inherit from BaseAgent, providing:
class BaseAgent(ABC):
"""Core agent interface"""
# Attributes
name: str # Agent identifier
description: str # Agent purpose
llm_client: OllamaClient # LLM interface
model: str # Model to use
system_prompt: str # Agent persona
tools: Dict[str, BaseTool] # Available tools
messages: List[Message] # Conversation history
# Core Methods
async def call_llm(prompt, messages, temperature) -> str
async def execute_tool(tool_name, **kwargs) -> ToolResult
async def process_task(task: Task) -> Task # Abstract
async def send_message(recipient: Agent, content: str) -> str
5.2 Specialized Agents
| Agent | Purpose | Model | Complexity |
|---|---|---|---|
| PlannerAgent | Task decomposition, dependency analysis | qwen2.5:14b | Complex |
| CriticAgent | Output validation, quality scoring | mistral:latest | Analysis |
| MemoryAgent | Context retrieval, episode storage | nomic-embed-text | Embeddings |
| VisionOCRAgent | Image/PDF text extraction | llava:7b | Vision |
| DocumentAnalysisAgent | Patent structure extraction | llama3.1:8b | Standard |
| MarketAnalysisAgent | Market opportunity identification | mistral:latest | Analysis |
| MatchmakingAgent | Stakeholder matching | qwen2.5:14b | Complex |
| OutreachAgent | Brief generation | llama3.1:8b | Standard |
5.3 Tool System
Tools extend agent capabilities:
class BaseTool(ABC):
name: str
description: str
parameters: Dict[str, ToolParameter]
async def execute(**kwargs) -> ToolResult
async def safe_execute(**kwargs) -> ToolResult # With error handling
Built-in Tools:
file_reader,file_writer,file_search,directory_listpython_executor,bash_executorgpu_monitor,gpu_selectdocument_generator_tool(PDF creation)
6. Workflow Engine
6.1 LangGraph StateGraph
The workflow is defined as a directed graph:
class SparknetWorkflow:
def _build_graph(self) -> StateGraph:
workflow = StateGraph(AgentState)
# Define nodes (processing functions)
workflow.add_node("planner", self._planner_node)
workflow.add_node("router", self._router_node)
workflow.add_node("executor", self._executor_node)
workflow.add_node("critic", self._critic_node)
workflow.add_node("refine", self._refine_node)
workflow.add_node("finish", self._finish_node)
# Define edges (transitions)
workflow.set_entry_point("planner")
workflow.add_edge("planner", "router")
workflow.add_edge("router", "executor")
workflow.add_edge("executor", "critic")
# Conditional routing based on validation
workflow.add_conditional_edges(
"critic",
self._should_refine,
{"refine": "refine", "finish": "finish"}
)
workflow.add_edge("refine", "planner") # Cyclic refinement
workflow.add_edge("finish", END)
return workflow
6.2 AgentState Schema
The shared state passed between nodes:
class AgentState(TypedDict):
# Message History (auto-managed by LangGraph)
messages: Annotated[Sequence[BaseMessage], add_messages]
# Task Information
task_id: str
task_description: str
scenario: ScenarioType # PATENT_WAKEUP, AGREEMENT_SAFETY, etc.
status: TaskStatus # PENDING β PLANNING β EXECUTING β VALIDATING β COMPLETED
# Workflow Execution
current_agent: Optional[str]
iteration_count: int
max_iterations: int
# Planning Outputs
subtasks: Optional[List[Dict]]
execution_order: Optional[List[List[str]]]
# Execution Outputs
agent_outputs: Dict[str, Any]
intermediate_results: List[Dict]
# Validation
validation_score: Optional[float]
validation_feedback: Optional[str]
validation_issues: List[str]
validation_suggestions: List[str]
# Memory Context
retrieved_context: List[Dict]
document_metadata: Dict[str, Any]
input_data: Dict[str, Any]
# Final Output
final_output: Optional[Any]
success: bool
error: Optional[str]
# Timing
start_time: datetime
end_time: Optional[datetime]
execution_time_seconds: Optional[float]
6.3 Workflow Execution Flow
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β WORKFLOW EXECUTION FLOW β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β β
β 1. PLANNER NODE β
β ββ Retrieve context from MemoryAgent β
β ββ Decompose task into subtasks β
β ββ Determine execution order (dependency resolution) β
β ββ Output: subtasks[], execution_order[] β
β β β
β βΌ β
β 2. ROUTER NODE β
β ββ Identify scenario type (PATENT_WAKEUP, etc.) β
β ββ Select appropriate executor agents β
β ββ Output: agents_to_use[] β
β β β
β βΌ β
β 3. EXECUTOR NODE β
β ββ Route to scenario-specific pipeline β
β β ββ Patent Wake-Up: Doc β Market β Match β Outreach β
β ββ Execute each specialized agent sequentially β
β ββ Output: agent_outputs{}, final_output β
β β β
β βΌ β
β 4. CRITIC NODE β
β ββ Validate output quality (0.0-1.0 score) β
β ββ Identify issues and suggestions β
β ββ Output: validation_score, validation_feedback β
β β β
β βΌ β
β 5. CONDITIONAL ROUTING β
β ββ IF score β₯ threshold (0.85) β FINISH β
β ββ IF iterations β₯ max β FINISH (with warning) β
β ββ ELSE β REFINE β back to PLANNER β
β β β
β βΌ β
β 6. FINISH NODE β
β ββ Store episode in MemoryAgent (if quality β₯ 0.75) β
β ββ Calculate execution statistics β
β ββ Return WorkflowOutput β
β β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
7. Implementation Details
7.1 LLM Integration (Ollama)
SPARKNET uses Ollama for local LLM deployment:
class LangChainOllamaClient:
"""LangChain-compatible Ollama client with model routing"""
COMPLEXITY_MODELS = {
"simple": "gemma2:2b", # Classification, routing
"standard": "llama3.1:8b", # General tasks
"analysis": "mistral:latest", # Analysis, reasoning
"complex": "qwen2.5:14b", # Complex multi-step
}
def get_llm(self, complexity: str) -> ChatOllama:
"""Get LLM instance for specified complexity level"""
model = self.COMPLEXITY_MODELS.get(complexity, "llama3.1:8b")
return ChatOllama(model=model, base_url=self.base_url)
def get_embeddings(self) -> OllamaEmbeddings:
"""Get embeddings model for vector operations"""
return OllamaEmbeddings(model="nomic-embed-text:latest")
7.2 Memory System (ChromaDB)
Three specialized collections:
class MemoryAgent:
def _initialize_collections(self):
# Episodic: Past workflow executions
self.episodic_memory = Chroma(
collection_name="episodic_memory",
embedding_function=self.embeddings,
persist_directory="data/vector_store/episodic"
)
# Semantic: Domain knowledge
self.semantic_memory = Chroma(
collection_name="semantic_memory",
embedding_function=self.embeddings,
persist_directory="data/vector_store/semantic"
)
# Stakeholders: Partner profiles
self.stakeholder_profiles = Chroma(
collection_name="stakeholder_profiles",
embedding_function=self.embeddings,
persist_directory="data/vector_store/stakeholders"
)
7.3 Pydantic Data Models
Structured outputs ensure type safety:
class PatentAnalysis(BaseModel):
patent_id: str
title: str
abstract: str
independent_claims: List[Claim]
dependent_claims: List[Claim]
ipc_classification: List[str]
technical_domains: List[str]
key_innovations: List[str]
trl_level: int = Field(ge=1, le=9)
trl_justification: str
commercialization_potential: str # High/Medium/Low
potential_applications: List[str]
confidence_score: float = Field(ge=0.0, le=1.0)
class MarketOpportunity(BaseModel):
sector: str
market_size_usd: Optional[float]
growth_rate_percent: Optional[float]
technology_fit: str # Excellent/Good/Fair
priority_score: float = Field(ge=0.0, le=1.0)
class StakeholderMatch(BaseModel):
stakeholder_name: str
stakeholder_type: str # Investor/Company/University
overall_fit_score: float
technical_fit: float
market_fit: float
geographic_fit: float
match_rationale: str
recommended_approach: str
8. Use Case: Patent Wake-Up
8.1 Scenario Overview
The Patent Wake-Up workflow transforms dormant patents into commercialization opportunities:
Patent Document β Analysis β Market Opportunities β Partner Matching β Valorization Brief
8.2 Pipeline Execution
async def _execute_patent_wakeup(self, state: AgentState) -> AgentState:
"""Four-stage Patent Wake-Up pipeline"""
# Stage 1: Document Analysis
doc_agent = DocumentAnalysisAgent(llm_client, memory_agent, vision_ocr_agent)
patent_analysis = await doc_agent.analyze_patent(patent_path)
# Output: PatentAnalysis (title, claims, TRL, innovations)
# Stage 2: Market Analysis
market_agent = MarketAnalysisAgent(llm_client, memory_agent)
market_analysis = await market_agent.analyze_market(patent_analysis)
# Output: MarketAnalysis (opportunities, sectors, strategy)
# Stage 3: Stakeholder Matching
matching_agent = MatchmakingAgent(llm_client, memory_agent)
matches = await matching_agent.find_matches(patent_analysis, market_analysis)
# Output: List[StakeholderMatch] (scored partners)
# Stage 4: Brief Generation
outreach_agent = OutreachAgent(llm_client, memory_agent)
brief = await outreach_agent.create_valorization_brief(
patent_analysis, market_analysis, matches
)
# Output: ValorizationBrief (markdown + PDF)
return state
8.3 Example Output
Patent: AI-Powered Drug Discovery Platform
βββββββββββββββββββββββββββββββββββββββββββββ
Technology Assessment:
TRL Level: 7/9 (System Demonstration)
Key Innovations:
β’ Novel neural network for molecular interaction prediction
β’ Transfer learning from existing drug databases
β’ Automated screening pipeline (60% time reduction)
Market Opportunities (Top 3):
1. Pharmaceutical R&D Automation ($150B market, 12% CAGR)
2. Biotechnology Platform Services ($45B market, 15% CAGR)
3. Clinical Trial Optimization ($8B market, 18% CAGR)
Top Partner Matches:
1. PharmaTech Solutions Inc. (Basel) - 92% fit score
2. BioVentures Capital (Toronto) - 88% fit score
3. European Patent Office Services (Munich) - 85% fit score
Output: outputs/valorization_brief_patent_20251204.pdf
9. Performance Considerations
9.1 Model Selection Strategy
| Task Complexity | Model | VRAM | Latency |
|---|---|---|---|
| Simple (routing, classification) | gemma2:2b | 1.6 GB | ~1s |
| Standard (extraction, generation) | llama3.1:8b | 4.9 GB | ~3s |
| Analysis (reasoning, evaluation) | mistral:latest | 4.4 GB | ~4s |
| Complex (planning, multi-step) | qwen2.5:14b | 9.0 GB | ~8s |
9.2 GPU Resource Management
class GPUManager:
"""Multi-GPU resource allocation"""
def select_best_gpu(self, min_memory_gb: float = 4.0) -> int:
"""Select GPU with most available memory"""
gpus = self.get_gpu_status()
available = [g for g in gpus if g.free_memory_gb >= min_memory_gb]
return max(available, key=lambda g: g.free_memory_gb).id
@contextmanager
def gpu_context(self, min_memory_gb: float):
"""Context manager for GPU allocation"""
gpu_id = self.select_best_gpu(min_memory_gb)
os.environ["CUDA_VISIBLE_DEVICES"] = str(gpu_id)
yield gpu_id
9.3 Workflow Timing
| Stage | Typical Duration | Notes |
|---|---|---|
| Planning | 5-10s | Depends on task complexity |
| Document Analysis | 15-30s | OCR adds ~10s for scanned PDFs |
| Market Analysis | 10-20s | Context retrieval included |
| Stakeholder Matching | 20-40s | Semantic search + scoring |
| Brief Generation | 15-25s | Includes PDF rendering |
| Validation | 5-10s | Per iteration |
| Total | 2-5 minutes | Single patent, no refinement |
9.4 Scalability
- Batch Processing: Process multiple patents in parallel
- ChromaDB Capacity: Supports 10,000+ stakeholder profiles
- Checkpointing: Resume failed workflows from last checkpoint
- Memory Persistence: Vector stores persist across sessions
10. Conclusion
10.1 Summary
SPARKNET demonstrates a practical implementation of agentic AI for research valorization:
- Multi-Agent Architecture: Specialized agents collaborate through shared state
- LangGraph Orchestration: Cyclic workflows with quality-driven refinement
- Local LLM Deployment: Privacy-preserving inference via Ollama
- Vector Memory: Contextual learning from past experiences
- Structured Outputs: Pydantic models ensure data integrity
10.2 Key Contributions
| Aspect | Innovation |
|---|---|
| Architecture | Hierarchical multi-agent system with conditional routing |
| Workflow | State machine with memory and iterative refinement |
| Memory | Tri-partite vector store (episodic, semantic, stakeholder) |
| Privacy | Full local deployment without cloud dependencies |
| Output | Professional PDF briefs with actionable recommendations |
10.3 Future Directions
- LangSmith Integration: Observability and debugging
- Real Stakeholder Database: CRM integration for live partner data
- Scenario Expansion: Agreement Safety, Partner Matching workflows
- Multi-Language Support: International patent processing
- Advanced Learning: Reinforcement learning from user feedback
Appendix A: Technology Stack
| Component | Technology | Version |
|---|---|---|
| Runtime | Python | 3.10+ |
| Orchestration | LangGraph | 0.2+ |
| LLM Framework | LangChain | 1.0+ |
| Local LLM | Ollama | Latest |
| Vector Store | ChromaDB | 1.3+ |
| API | FastAPI | 0.100+ |
| Frontend | Next.js | 16+ |
| Validation | Pydantic | 2.0+ |
Appendix B: Model Requirements
# Required models (download via Ollama)
ollama pull llama3.1:8b # Standard tasks (4.9 GB)
ollama pull mistral:latest # Analysis tasks (4.4 GB)
ollama pull qwen2.5:14b # Complex reasoning (9.0 GB)
ollama pull gemma2:2b # Simple routing (1.6 GB)
ollama pull nomic-embed-text # Embeddings (274 MB)
ollama pull llava:7b # Vision/OCR (optional, 4.7 GB)
Appendix C: Running SPARKNET
# 1. Start Ollama server
ollama serve
# 2. Activate environment
conda activate sparknet
# 3. Start backend
cd /home/mhamdan/SPARKNET
python -m uvicorn api.main:app --reload --port 8000
# 4. Start frontend (separate terminal)
cd frontend && npm run dev
# 5. Access application
# Frontend: http://localhost:3000
# API Docs: http://localhost:8000/api/docs
Document Generated: December 2025 SPARKNET Version: 1.0 (Production Ready)