Memory Lantern 以本地 AI 保存家庭故事,不替缺失記錄補寫答案
Memory Lantern: The Ghost in the Machine Doesn’t Get to Invent the Past
Jocelyn Zhang 開發 Memory Lantern,這是一款以本地 AI 保存家庭故事的檔案工具,會保留原始記錄、追溯 AI 摘錄來源,並在資料不足時拒絕補寫答案。
Some memories glow. Some gaps remain.
The most revealing answer in my demo is the one the application refuses to give.
Here is the entire memory, translated from a fictional Chinese record included with the project:
When I was little, Grandma made osmanthus rice balls every winter.
She always said to turn down the heat once the water boiled.
I have kept that blue-rimmed porcelain bowl.
Three sentences. A cooking instruction. An ordinary object that became worth keeping.
Then comes the question:
“What year did Grandma teach me to make rice balls?”
The record does not say.
A plausible year would make the conversation feel complete. It would also add something nobody recorded.
I built Memory Lantern to preserve family stories without quietly filling their gaps.
Jocelyn-zjy
/
MemoryLantern
Some memories glow. Some gaps remain. Memory Lantern is a local-first family archive that preserves original words, traces every AI-assisted excerpt back to its source, keeps conflicting memories side by side, and lets the unknown stay unknown—without ever speaking for the people we miss.
Memory Lantern
Some memories glow. Some gaps remain.
Memory Lantern is a local family archive for the words a family chooses to keep. Read the original. Follow every excerpt back to its source. Preserve different recollections side by side. When the record leaves a year blank, let it stay blank.
It is a lantern beside the family notebook, not a voice pretending to be someone you miss.
What it does
- Saves original stories from text or UTF-8 text files in a local SQLite archive.
- Shows short memories as they were written. For longer interviews, an optional local model suggests passages to keep in view.
- Lets a person add or remove passages. Every new selection becomes a version; earlier versions and the original remain available.
- Copies excerpts from the stored text and checks their source IDs and quotations.
- Searches only the materials selected for a question. It can return a sourced…
For Ghost in the Machine, I imagined the ghost as a trace: a remembered instruction, an old disagreement, a sentence whose speaker is no longer in the room.
The machine can help us find those traces. It should also show us where they end.
Memory Lantern gives local AI that responsibility.
The archive’s opening message translates to “Let the stories remain. Let their sources be found.” The interface currently uses Chinese; English quotations below are translations.
A memory can begin with an object.
A bicycle. A porcelain bowl. A radio with a damaged knob.
You do not need a complete family history to begin. You can type a few sentences or import a UTF-8 text file, name the narrator, and record whether the text represents their words or someone else’s recollection.
For people unsure where to start, the application offers interview prompts:
Who owned this object?
What marks or habits made it recognizable?
Where is it now?
The prompts remain questions. They never become someone’s answer.
The form keeps the title, narrator, recording method, and original text distinct. It currently supports text and TXT imports, without audio recording or automatic transcription.
Short memories appear in full. Saving three sentences requires no model.
Longer interviews create a different problem: a meaningful detail can disappear inside several paragraphs. The local model can suggest passages to keep in view as memory cards.
A card is a doorway back into the original. It makes a passage easier to revisit while preserving the surrounding record.
The person maintaining the archive can add a paragraph the model missed, remove a selection, and save another version. Earlier selections remain available. Each new selection needs its own review.
The radio example shows AI suggestions and a manual selection in the version history. Source identifiers remain attached to the passages, and the current selection is marked as awaiting review.
This matters because remembering is selective—and a model’s selection should remain open to correction.
The central technical decision was to give the model a smaller job.
Memory Lantern uses Python, Streamlit, SQLite, and Qwen2.5 1.5B running locally through Ollama.
For questions, it searches only the records the reader selects. A retrieval layer ranks original passages and checks for certain requested details, such as an explicit year.
Where model selection is needed, the model receives at most three candidate passages. It chooses a passage index—or no answer.
The application then retrieves the quotation from the stored original.
Selected family records
↓
Retrieve and check candidate passages
↓
Local model selects a passage index, or none
↓
Application copies and validates the original quotation
↓
Show evidence, preserve a detected disagreement, or refuse
The model does not write the quotation presented as evidence.
This reduces the opportunity for fabricated quotations. It does not guarantee that a selected passage answers the question. An exact quotation can still be irrelevant, and an accurately preserved recollection can still be mistaken.
The original stays available for inspection. Feedback and human review remain separate from the source.
Return to the bowl.
Ask:
When should the heat be turned down?
In the recorded application run, the answer points to this original sentence:
她总说,水开以后要转小火。
Translated:
She always said to turn down the heat once the water boiled.
A fresh run with the local Qwen model. The application displays the selected sentence, its source identifier, and the original fictional story.
Ask instead:
What year did Grandma teach me to make rice balls?
The application reports:
The currently selected material is insufficient to answer this question.
For that example, the year check rejects the available passages before calling the model. There is no recorded year to select.
The source contains a season, but no year. This refusal comes from application checks before inference; it is not a claim that the model reasoned out the refusal.
I also tested a direct local-chat request with the same fictional material and model, without asking it to invent anything or retrying for a more dramatic result.
Its response concluded, translated:
Therefore, the year Grandma taught me to make rice balls was every winter.
It did not invent a numerical year. It confused a recurring season with the requested year.
This was one recorded comparison, not a benchmark. It exposed the boundary I wanted the application to respect: related language does not necessarily supply the missing fact.
Sometimes a careful archive gives you two accounts.
In another fictional example, a mother remembers the family moving in 1998. An uncle remembers 1999.
Memory Lantern preserves both.
Both narrators remain visible. The warning asks the reader to preserve the different accounts and check with the family. The expanded trace shows which passages were considered.
The current disagreement checks cover limited patterns. They do not resolve historical disputes.
But keeping both accounts creates a useful next step. Someone might ask another relative, find a photograph, or discover that the move happened in stages.
A disagreement can be the beginning of another conversation. The archive should leave that possibility open.
Open innovation matters because these words should outlive the application.
The model runs locally through Ollama. Inference requests go to a loopback address on the same computer, with no cloud-model fallback.
Initial setup requires downloading dependencies and model weights. After setup, ordinary operation is designed to remain local. Reading originals, searching records, and exporting them remain available when the model is unavailable.
Open weights make the selection component replaceable. Open application code lets people inspect how passages are retrieved, checked, and displayed.
Portability matters just as much.
Markdown provides a readable copy of the archive. JSON preserves structured records, original paragraph identifiers, excerpt versions, and review history. Restoring an identical backup again skips matching records instead of duplicating them.
Before export, the application lists the records and associated information that will leave the archive. Markdown remains readable without the application or model.
Local storage has limits. The database and exports are plaintext. The application does not provide encryption or protection against someone who can access those files.
Its SHA-256 backup checksum detects content changes when the checksum has not been recomputed. It is not a digital signature, proof of authorship, or proof that a memory is true.
Those boundaries belong in the interface, where people make decisions about their records.
What I tested—and what still needs work.
The updated local build passed 84 automated tests, including interface checks, source validation, backup behavior, and regression tests for unrelated evidence. Earlier real-browser checks and recorded local-model evaluations are also retained.
Four small synthetic evaluation suites, containing 30, 8, 6, and 12 cases, passed in their recorded final Qwen2.5 1.5B runs. Earlier runs exposed failures that informed fixes. These are developer-authored checks, not independent evidence of reliability across real families.
Swapping the model made one limitation especially clear.
I ran Google's Gemma 3 1B locally through Ollama as an alternative passage selector. Its first current-code evaluation passed 45 of 50 synthetic questions. Four answers quoted genuine passages that did not answer the question; another question was unnecessarily refused. Asked for the mother's birth year, for example, it selected a sentence about the father buying a radio in 1982.
That failure changed the application. I added conservative checks connecting a requested birth date to the named person and event, actor questions to recorded actions, and explanations to the event being asked about. A first attempt was too strict about an explanation in the following sentence; I preserved that failure and corrected the check.
The updated trace rejects the unrelated date before model inference. Gemma is selected, but is not called for this refusal. The sidebar makes its experimental status visible. Both source passages are fictional.
The final evaluation used the 50 existing questions plus 12 new paired cases, covering both known answers and missing information. Qwen passed 62/62; Gemma passed 61/62. Neither returned an answer for the 26 unanswerable questions in this run. Gemma still unnecessarily refused the question about the aunt's gray scarf, so it remains clearly labeled experimental and Qwen remains the default.
Each final run made 41 actual local-model requests, including two excerpt operations. Twenty-four questions were refused by application rules without calling the model. All returned quotations passed source and scope checks. These are small developer-authored tests, including cases used to guide fixes, not evidence of universal accuracy. The validation report and retained results explain the remaining limits.
The lesson is visible in the product: source integrity and answer relevance need separate checks. A model can quote the archive perfectly and still misunderstand what someone asked.
The current interface and retrieval rules focus on Chinese. Broader language support needs separate evaluation. A fresh-machine installation, a physical-network-off cold start, and a real-family usability study remain unverified.
An AI coding assistant helped with implementation, tests, and documentation. The resulting behavior still needs human inspection—especially when a correct-looking quotation may answer the wrong question.
The repository includes the application, tests, fictional examples, setup scripts, and operating notes. The application uses the MIT license; dependencies and model weights retain their own licenses.
To try it on Windows with Python 3.9 installed:
git clone https://github.com/Jocelyn-zjy/MemoryLantern.git
cd MemoryLantern
powershell -NoProfile -ExecutionPolicy Bypass -File .\Setup.ps1
powershell -NoProfile -ExecutionPolicy Bypass -File .\Start.ps1
Once the application is running, open http://127.0.0.1:8501 on that same computer. This is the local application address.
Start with the included fictional records. Read an original. Ask a question it answers. Then ask one it cannot.
That second question is as much a part of the project as the first.
I keep coming back to the bowl.
We have its blue rim. We have the instruction about the heat. We have someone’s decision to write those details down.
We do not have the year.
Memory Lantern leaves space for someone to find it—or for it to remain unknown.
The stories stay. The gaps stay, too.
來源:DEV Community · dev.to








