DeerFlow Persona Engine
2026-03-252 turns13,491 charsgpt-5-3
Summary
User is building a DeerFlow persona query engine to retrieve documents and generate responses in specific or blended persona voices.
Messages
rewrite: # DeerFlow Persona Query Engine
Query your document bank and get responses in specific personas' voices. Blend personas to create hybrid voices. Built for Daniel's 4,865-document DeerFlow bank.
## Architecture
```
┌─────────────────────────────────────────────────────────────┐
│ Persona Query Engine │
├─────────────────────────────────────────────────────────────┤
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────────┐ │
│ │ FastAPI │ │ Streamlit │ │ Python Client │ │
│ │ Server │ │ UI │ │ │ │
│ └──────┬───────┘ └──────────────┘ └──────────────────┘ │
│ │ │
│ ┌──────▼───────┐ │
│ │ Query │ │
│ │ Engine │ │
│ └──────┬───────┘ │
│ │ │
│ ┌──────▼─────────────────────────────────┐ │
│ │ DeerFlow Bank (4,865 docs) │ │
│ │ - documents/ │ │
│ │ - metadata/index.json │ │
│ │ - vectors/ │ │
│ └────────────────────────────────────────┘ │
│ │ │
│ ┌──────▼───────┐ ┌──────────────┐ ┌──────────────────┐ │
│ │ Persona │ │ Persona │ │ Style │ │
│ │ Extractor │ │ Blender │ │ Engine │ │
│ └──────────────┘ └──────────────┘ └──────────────────┘ │
│ │ │
│ ┌──────▼───────┐ │
│ │ Ollama │ (llama3.2 or gemma-3) │
│ └──────────────┘ │
└─────────────────────────────────────────────────────────────┘
```
## Quick Start
### 1. Install dependencies
```bash
pip install fastapi uvicorn ollama streamlit requests pydantic
```
### 2. Start the API server
```bash
python persona_api.py
```
Server runs on `http://localhost:8000`
### 3. Start the UI (optional)
```bash
streamlit run persona_ui.py
```
UI runs on `http://localhost:8501`
### 4. Query via API
```bash
# Query in KonradFreeman's voice
curl -X POST http://localhost:8000/query \
-H "Content-Type: application/json" \
-d '{
"query": "What do you think about local-first AI?",
"persona": "KonradFreeman"
}'
# Blend personas
curl -X POST http://localhost:8000/query \
-H "Content-Type: application/json" \
-d '{
"query": "How should I approach building an AI startup?",
"blended_persona": [
{"KonradFreeman": 0.7},
{"Daniel": 0.3}
]
}'
```
## API Endpoints
### POST /query
Query the bank with persona styling.
**Request:**
```json
{
"query": "string",
"persona": "string (optional)",
"blended_persona": [{"author": weight}, ...],
"search_mode": "hybrid|keyword|author"
}
```
**Response:**
```json
{
"success": true,
"query": "original query",
"persona_used": "KonradFreeman",
"documents_found": 12,
"content": "Styled response...",
"source_documents": ["id1", "id2"],
"persona_json": {...}
}
```
### POST /extract
Extract a persona from an author's documents.
```json
{
"author": "KonradFreeman"
}
```
### POST /blend
Blend multiple personas.
```json
{
"personas": [
{"KonradFreeman": 0.7},
{"Daniel": 0.3}
]
}
```
### GET /personas
List all cached personas.
### GET /persona/{author}
Get a specific persona's JSON.
### POST /batch-extract
Extract personas for all authors in the bank.
## Usage Examples
### Python Client
```python
from deerflow_persona_query import PersonaQueryEngine
from ollama import chat
def ollama_llm(prompt, system=""):
response = chat(
model="llama3.2",
messages=[
{"role": "system", "content": system},
{"role": "user", "content": prompt}
]
)
return response["message"]["content"]
# Initialize
engine = PersonaQueryEngine(
bank_path="/mnt/user-data/uploads/bank",
llm_callable=ollama_llm,
cache_path="/mnt/user-data/workspace/personas"
)
# Query in a persona's voice
result = engine.query(
"What do you think about RAG?",
persona="KonradFreeman"
)
print(result.content)
# Blend personas
result = engine.query(
"Should I use local LLMs or cloud APIs?",
blended_persona=[("KonradFreeman", 0.6), ("Daniel", 0.4)]
)
print(result.content)
# Extract all personas
engine.extract_all_personas()
```
## Persona Schema
Each persona contains:
```json
{
"name": "KonradFreeman",
"author": "KonradFreeman",
"tone": "analytical, skeptical, conversational",
"vocabulary_level": "technical",
"sentence_structure": "varied with short punchy sentences",
"psychological_traits": ["curious", "skeptical", "pragmatic"],
"common_themes": ["AI", "local-first", "RAG", "Ollama"],
"references": ["Ollama", "LangChain", "Konrad"],
"anti_patterns": ["corporate speak", "over-explaining"],
"formality_score": 0.4,
"humor_score": 0.6,
"technical_depth": 0.8,
"emotional_warmth": 0.5,
"reasoning_style": "iterative, builds from small pieces",
"source_documents": ["mdzvfl6", "..."]
}
```
## Configuration
Environment variables:
- `BANK_PATH`: Path to DeerFlow bank (default: `/mnt/user-data/uploads/bank`)
- `PERSONA_CACHE`: Path to cache personas (default: `/mnt/user-data/workspace/personas`)
- `OLLAMA_MODEL`: Ollama model to use (default: `llama3.2`)
## Next Steps
1. **Extract all personas** from your bank:
```bash
curl -X POST http://localhost:8000/batch-extract
```
2. **Test queries** in different voices:
- KonradFreeman (technical, skeptical)
- Your own voice
- Blend them
3. **Rebuild UI** in Next.js + shadcn for production
4. **Add RLHF loop**: Let users rate outputs, adjust persona weights automatically
5. **Integrate with your existing chat app**: Use this as the style engine backend
## How It Works
1. **Persona Extraction**: LLM analyzes documents by an author, outputs structured JSON describing their voice
2. **Persona Blending**: Weighted combination of multiple personas, normalizing scores and deduplicating traits
3. **Style Application**: Retrieved documents are summarized/rewritten using the persona's JSON as a system prompt
4. **Caching**: Extracted personas are cached as JSON files for fast retrieval
## Files
- `personagen_engine.py`: Core Persona dataclass, Extractor, Blender, StyleEngine
- `deerflow_persona_query.py`: DeerFlow bank interface, query engine
- `persona_api.py`: FastAPI server
- `persona_ui.py`: Streamlit UI (prototype)
## License
MIT - Build on it, break it, make it yours.
# DeerFlow Persona Query Engine
Turn your document bank into a voice-driven intelligence system. Query your data and get answers in any author’s voice or blend multiple personas into something entirely new. Built on Daniel’s 4,865-document DeerFlow corpus.
## Architecture
```
┌─────────────────────────────────────────────────────────────┐
│ Persona Query Engine │
├─────────────────────────────────────────────────────────────┤
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────────┐ │
│ │ FastAPI │ │ Streamlit │ │ Python Client │ │
│ │ Server │ │ Interface │ │ │ │
│ └──────┬───────┘ └──────────────┘ └──────────────────┘ │
│ │ │
│ ┌──────▼───────┐ │
│ │ Query │ │
│ │ Engine │ │
│ └──────┬───────┘ │
│ │ │
│ ┌──────▼─────────────────────────────────┐ │
│ │ DeerFlow Bank (4,865 docs) │ │
│ │ - documents/ │ │
│ │ - metadata/index.json │ │
│ │ - vectors/ │ │
│ └────────────────────────────────────────┘ │
│ │ │
│ ┌──────▼───────┐ ┌──────────────┐ ┌──────────────────┐ │
│ │ Persona │ │ Persona │ │ Style │ │
│ │ Extractor │ │ Blender │ │ Engine │ │
│ └──────────────┘ └──────────────┘ └──────────────────┘ │
│ │ │
│ ┌──────▼───────┐ │
│ │ Ollama │ (llama3.2 / gemma-3) │
│ └──────────────┘ │
└─────────────────────────────────────────────────────────────┘
```
## Quick Start
### 1. Install dependencies
```bash
pip install fastapi uvicorn ollama streamlit requests pydantic
```
### 2. Launch the API
```bash
python persona_api.py
```
Runs on `http://localhost:8000`
### 3. Launch the UI (optional)
```bash
streamlit run persona_ui.py
```
Runs on `http://localhost:8501`
### 4. Query the system
```bash
# Single persona
curl -X POST http://localhost:8000/query \
-H "Content-Type: application/json" \
-d '{
"query": "What do you think about local-first AI?",
"persona": "KonradFreeman"
}'
# Blended personas
curl -X POST http://localhost:8000/query \
-H "Content-Type: application/json" \
-d '{
"query": "How should I approach building an AI startup?",
"blended_persona": [
{"KonradFreeman": 0.7},
{"Daniel": 0.3}
]
}'
```
## API
### POST `/query`
Run a query with persona styling.
**Request**
```json
{
"query": "string",
"persona": "optional string",
"blended_persona": [{"author": weight}],
"search_mode": "hybrid | keyword | author"
}
```
**Response**
```json
{
"success": true,
"query": "original query",
"persona_used": "KonradFreeman",
"documents_found": 12,
"content": "styled response",
"source_documents": ["id1", "id2"],
"persona_json": {}
}
```
---
### POST `/extract`
Generate a persona profile from an author’s documents.
```json
{
"author": "KonradFreeman"
}
```
### POST `/blend`
Combine multiple personas into a weighted composite.
```json
{
"personas": [
{"KonradFreeman": 0.7},
{"Daniel": 0.3}
]
}
```
### GET `/personas`
List cached personas.
### GET `/persona/{author}`
Retrieve a persona JSON.
### POST `/batch-extract`
Extract personas for the entire corpus.
---
## Python Client
```python
from deerflow_persona_query import PersonaQueryEngine
from ollama import chat
def ollama_llm(prompt, system=""):
response = chat(
model="llama3.2",
messages=[
{"role": "system", "content": system},
{"role": "user", "content": prompt}
]
)
return response["message"]["content"]
engine = PersonaQueryEngine(
bank_path="/mnt/user-data/uploads/bank",
llm_callable=ollama_llm,
cache_path="/mnt/user-data/workspace/personas"
)
# Single persona
result = engine.query(
"What do you think about RAG?",
persona="KonradFreeman"
)
print(result.content)
# Blended personas
result = engine.query(
"Local LLMs vs cloud APIs?",
blended_persona=[("KonradFreeman", 0.6), ("Daniel", 0.4)]
)
print(result.content)
# Extract all personas
engine.extract_all_personas()
```
## Persona Schema
Each persona is a structured representation of voice and thinking patterns:
```json
{
"name": "KonradFreeman",
"author": "KonradFreeman",
"tone": "analytical, skeptical, conversational",
"vocabulary_level": "technical",
"sentence_structure": "short, punchy, varied",
"psychological_traits": ["curious", "skeptical", "pragmatic"],
"common_themes": ["AI", "local-first", "RAG", "Ollama"],
"references": ["Ollama", "LangChain"],
"anti_patterns": ["corporate speak", "over-explaining"],
"formality_score": 0.4,
"humor_score": 0.6,
"technical_depth": 0.8,
"emotional_warmth": 0.5,
"reasoning_style": "iterative, builds from primitives",
"source_documents": ["mdzvfl6"]
}
```
## Configuration
Environment variables:
- `BANK_PATH` → document store (default: `/mnt/user-data/uploads/bank`)
- `PERSONA_CACHE` → persona cache (default: `/mnt/user-data/workspace/personas`)
- `OLLAMA_MODEL` → model selection (default: `llama3.2`)
## Roadmap
- Extract personas across the full corpus
- Stress test voice consistency across queries
- Replace Streamlit with Next.js + shadcn UI
- Add feedback loop for dynamic persona tuning
- Plug into existing chat systems as a style backend
## How It Works
Persona extraction converts raw writing into structured voice profiles. Blending merges multiple profiles into weighted hybrids. The engine retrieves relevant documents, then rewrites or summarizes them through the selected persona lens. Extracted personas are cached for speed, turning style into a reusable primitive.
## Project Structure
- `personagen_engine.py` → core logic (extractor, blender, style engine)
- `deerflow_persona_query.py` → query interface
- `persona_api.py` → FastAPI server
- `persona_ui.py` → Streamlit prototype
## License
MIT. Use it, modify it, break it, rebuild it.
gpt-5-3