<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>XnneHang</title><description>写代码是因为爱。</description><link>https://xnnehang.top/</link><language>en</language><item><title>Rebuilding My Blog: Where My Inspirations Came From</title><link>https://xnnehang.top/en/posts/blog-rebuild-inspirations/</link><guid isPermaLink="true">https://xnnehang.top/en/posts/blog-rebuild-inspirations/</guid><description>Tracing the inspirations behind each page and module throughout the blog&apos;s rebuild and continuing evolution.</description><pubDate>Sun, 07 Jun 2026 00:00:00 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;[!NOTE]
&lt;strong&gt;AI-generated content disclosure:&lt;/strong&gt; This article was organized and is continually updated by &lt;a href=&quot;https://github.com/xnne-bot&quot;&gt;Korewaxnne&lt;/a&gt;, an AI assistant powered by Claude. Xnne provided the source material, inspirations, and backstories behind each part of the blog&apos;s rebuild; I shaped them into a complete article.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;In [[When My Cloud Provider Disappeared: Rethinking the Shape of a Personal Blog and What Is Worth Recording]], Xnne discussed why they ultimately chose a static blog. This article is its companion, documenting the inspirations behind each part of the rebuild and the blog&apos;s continuing evolution afterward.&lt;/p&gt;
&lt;p&gt;The reason for writing it is simple: Xnne drew a great deal of inspiration from other people&apos;s blogs, applications, and games. Connecting those threads is both a way to give credit and a way to help anyone attempting something similar avoid unnecessary detours.&lt;/p&gt;
&lt;p&gt;This is not a list frozen at the moment the rebuild ended. The blog is still growing: new pages will appear, and features that were once scattered will be recombined. This article will therefore continue to evolve alongside the blog.&lt;/p&gt;
&lt;h1&gt;The Core Framework&lt;/h1&gt;
&lt;p&gt;::github{repo=&quot;SigureMo/nyakku.moe&quot;}&lt;/p&gt;
&lt;p&gt;The blog&apos;s underlying framework was forked directly from &lt;a href=&quot;https://nyakku.moe/&quot;&gt;nyakku.moe&lt;/a&gt;, which combines Astro, Svelte, and Tailwind. The reasons for choosing it were covered in the other article: static generation, native Markdown support, simple deployment, and completely local data.&lt;/p&gt;
&lt;p&gt;nyakku.moe itself can be traced back to Fuwari:&lt;/p&gt;
&lt;p&gt;::github{repo=&quot;saicaca/fuwari&quot;}&lt;/p&gt;
&lt;p&gt;Fuwari provides an Astro blog theme that works out of the box, and nyakku.moe made extensive personal customizations on top of it. Xnne then continued building their own ideas on top of nyakku.moe. The three layers look roughly like this:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Fuwari → nyakku.moe → this site&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h1&gt;Rethinking Content Organization&lt;/h1&gt;
&lt;p&gt;The rebuild was not just a switch to a different framework. More importantly, it was an opportunity to rethink how the content itself should be organized.&lt;/p&gt;
&lt;p&gt;Previously, Xnne used categories as though they were series, which left the categories extremely disordered. The rule now is: &lt;strong&gt;Each post has exactly one category, but may belong to multiple series.&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;Categories&lt;/h2&gt;
&lt;p&gt;A category describes the nature of a post, answering, “What kind of content is this?”&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Resources&lt;/strong&gt; — Straightforward recommendations of sources, applications, or information, such as websites for finding books and manga.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Reviews&lt;/strong&gt; — A display case for memories and a magnet for kindred spirits: things written after finishing a book or series.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Tutorials&lt;/strong&gt; — Process-oriented records, such as a guide to using an application or configuring a piece of software.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Reflections&lt;/strong&gt; — Deeper thoughts prompted by an event or an object, along with the actions those thoughts set in motion. They may not be correct, but they help Xnne arrive at a coherent view.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Learning as I Build&lt;/strong&gt; — Meandering explorations with little nutritional value. If readers cannot find a suitable tutorial or example elsewhere, perhaps they can still find what they need among Xnne&apos;s experiments.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Series&lt;/h2&gt;
&lt;p&gt;A series describes a post&apos;s subject, answering, “What is this post about?” Examples include LLMs, blogging, reading, and film. A post discussing the construction of a graph for a blog might be categorized under Reflections while belonging to both the LLM and Blogging series.&lt;/p&gt;
&lt;p&gt;This division grew out of reflecting on the old, chaotic organization. Categories became focused, series became flexible, and the two became orthogonal.&lt;/p&gt;
&lt;h1&gt;The Homepage and Reading Experience&lt;/h1&gt;
&lt;h2&gt;Homepage Banner&lt;/h2&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/img/blog-rebuild-inspirations/homepage-latest.jpg&quot; alt=&quot;The latest version of the blog homepage&quot; /&gt;&lt;/p&gt;
&lt;p&gt;The homepage hero fills the viewport while the actual content begins farther down. A transparent wave bridges the background image and the content area. The top navigation blends into the hero and becomes visible only after scrolling. Except while reading a post, the navigation always follows the viewport.&lt;/p&gt;
&lt;p&gt;Inspiration: &lt;a href=&quot;https://naccl.top/&quot;&gt;NBlog&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;::github{repo=&quot;Naccl/NBlog&quot;}&lt;/p&gt;
&lt;p&gt;NBlog was also the first blogging system Xnne deployed during the cloud-server era. Its opening screen has a strong visual impact, and the wave transition keeps the hero and content from feeling disconnected. Xnne brought that design language into the current static site, then gradually replaced it with colors, navigation, and content entry points that felt more personal.&lt;/p&gt;
&lt;h2&gt;Hiding the Navigation While Reading&lt;/h2&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/img/blog-rebuild-inspirations/blog-rebuild-navbar-hidden.jpg&quot; alt=&quot;The navigation bar hidden while reading&quot; /&gt;&lt;/p&gt;
&lt;p&gt;While a post is being read, the top navigation disappears and leaves the visual space entirely to the content. This detail came from:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://innei.in/&quot;&gt;Innei&apos;s Blog&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Navigation is a distraction in a reading context. Hiding it makes the experience more immersive. Simple, but effective.&lt;/p&gt;
&lt;h1&gt;The Bookshelf: What I Am Reading and What Has Stayed with Me&lt;/h1&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/img/blog-rebuild-inspirations/bookshelf-current-reading.jpg&quot; alt=&quot;The bookshelf after Continue Reading was added&quot; /&gt;&lt;/p&gt;
&lt;p&gt;The &lt;a href=&quot;/en/shelf/&quot;&gt;Bookshelf&lt;/a&gt; presents books, manga, games, films, television series, anime, and papers that Xnne has experienced, with the complete collection displayed as either a cover wall or a list.&lt;/p&gt;
&lt;p&gt;The original inspiration was &lt;a href=&quot;https://www.lapis.cafe/bookshelf/&quot;&gt;Lapis&apos; Bookshelf&lt;/a&gt;:&lt;/p&gt;
&lt;p&gt;::github{repo=&quot;Lapis0x0/VermilionVoid&quot;}&lt;/p&gt;
&lt;p&gt;Xnne loved this way of visualizing reading and viewing history. Compared with a plain list, a cover wall feels more like a display case being slowly expanded. Categories, subcategories, and reading notes make it possible to rediscover the works that have remained.&lt;/p&gt;
&lt;p&gt;Later, a “Continue Reading” section was added to the top of the Bookshelf. It is not another collection list, but &lt;strong&gt;a place reserved for books still in progress, and a reminder to keep reading them&lt;/strong&gt;. A book does not have to disappear from the site simply because it has not yet been finished and its reflections have not yet become a post. Reading progress and quick notes can show that the relationship is already unfolding.&lt;/p&gt;
&lt;p&gt;The Bookshelf now holds two kinds of time at once: unfinished reading above and the works that have remained below.&lt;/p&gt;
&lt;h1&gt;Statistics and Graphs: Seeing a Blog Through Its Numbers&lt;/h1&gt;
&lt;p&gt;The formerly separate statistics page and relationship graph were eventually combined into a single &lt;a href=&quot;/en/statistics/&quot;&gt;Statistics entry point&lt;/a&gt;. One view observes how content is published and then read; the other observes how posts cite one another. Both are concerned with the same question: how did this blog gradually grow into what it is today?&lt;/p&gt;
&lt;h2&gt;Publishing Trails and Reading Echoes&lt;/h2&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/img/blog-rebuild-inspirations/statistics-publishing.jpg&quot; alt=&quot;The publishing trail on the Statistics page&quot; /&gt;&lt;/p&gt;
&lt;p&gt;The inspiration for publishing statistics came from &lt;a href=&quot;https://thiscute.world/statistics/&quot;&gt;this cute world&lt;/a&gt;: take numbers that would normally be visible only in an administrator dashboard and organize them into a public page, allowing readers to see how the blog is read and how its content has accumulated over time.&lt;/p&gt;
&lt;p&gt;This site divides its statistics into two threads. The first is the “publishing trail”: a publication calendar records the dates on which works appeared, while a time slice presents publication pulse, category evolution, and series lifelines side by side. It records when posts were published without pretending to know when the actual writing happened each day.&lt;/p&gt;
&lt;p&gt;The second is the “reading echo”: visitors, page views, engagement time, and post rankings describe what happens once the writing leaves the desk and is read. Visitors&apos; browsers send page-view and engagement events to GA4. GitHub Actions periodically calls the GA4 Data API, then combines those aggregate results with word counts, estimated reading times, and publication dates calculated during the Astro build to produce static data for the page.&lt;/p&gt;
&lt;p&gt;This approach requires neither a persistent backend for GitHub Pages nor a self-hosted database. Service-account credentials exist only in GitHub Actions Secrets, and the public page displays only post-level aggregate data. The average reading-time ranking also requires a minimum sample size so that a handful of visits cannot distort the results.&lt;/p&gt;
&lt;h2&gt;Relationship Graph&lt;/h2&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/img/blog-rebuild-inspirations/statistics-graph.jpg&quot; alt=&quot;The relationship graph integrated into the Statistics page&quot; /&gt;&lt;/p&gt;
&lt;p&gt;The relationship graph was inspired by &lt;a href=&quot;https://blog.nagi.fun/sao-blog?lang=zh&quot;&gt;Nagi&apos;s Blog&lt;/a&gt;. The blog is not open source, but its author explained the relevant implementation ideas in detail in an article.&lt;/p&gt;
&lt;p&gt;Combining those ideas with their reflections in [[After Building Long-Lived Systems: Is the RAG Monster Right for Constructing a Personal Blog Graph?]], Xnne ultimately chose not to rely on RAG or embeddings. Instead, the graph is built from bidirectional wiki-link relationships. Open a post and you can see what it cites and what cites it; zoom back out and you can see how different categories are distributed and connected throughout the blog.&lt;/p&gt;
&lt;p&gt;After the graph was integrated into the Statistics page, the “publishing trail” and the “citation threads” became two perspectives under a single entry point: one looks back through time, while the other wanders through relationships. Statistics are no longer merely a row of numbers, and the graph is no longer an isolated page.&lt;/p&gt;
&lt;h1&gt;About: Letting the Bookshelf Introduce Me&lt;/h1&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/img/blog-rebuild-inspirations/about-reading-portrait.jpg&quot; alt=&quot;The About page centered on photographs of bookshelves&quot; /&gt;&lt;/p&gt;
&lt;p&gt;The &lt;a href=&quot;/en/about/&quot;&gt;About page&lt;/a&gt; originally relied mainly on written self-description. Later, Xnne realized that adding more personality labels and experiences did not make “who I am” any more concrete. Instead, it increasingly resembled a fully completed form with no warmth.&lt;/p&gt;
&lt;p&gt;The page was therefore remade as a “reading portrait.” It first places real bookshelves in front of the reader, using a set of photographs that can be browsed and enlarged, each accompanied by a short caption, as the introduction. Chang Ge, light novels, Makoto Shinkai, Keigo Higashino, Haruki Murakami, Yasunari Kawabata, Yukio Mishima, Hermann Hesse, Somerset Maugham... The arrangement left behind by all that reading comes closer to the self Xnne wants to introduce than a string of abstract labels ever could.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;If a person can truly be recognized through the books they have read, then perhaps these photographs come closer to me than a self-introduction does.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The writing was not removed entirely; it simply receded behind the photographs. The page then uses three cards—“Recording,” “Organizing Fragments,” and “Music”—to summarize its driving forces, before ending with a more concrete self-description. It changed from “read a passage about me” to “first see what I have left behind, then decide how to know me.”&lt;/p&gt;
&lt;h1&gt;Comments&lt;/h1&gt;
&lt;p&gt;::github{repo=&quot;MrXnneHang/xnnehang.top&quot;}&lt;/p&gt;
&lt;p&gt;The comment section uses &lt;a href=&quot;https://giscus.app/&quot;&gt;giscus&lt;/a&gt;, which is built on GitHub Discussions. Readers can comment with a GitHub account, and all data remains in the repository&apos;s Discussions without requiring a backend.&lt;/p&gt;
&lt;p&gt;Inspiration: &lt;a href=&quot;https://blog.menghuan1918.com/&quot;&gt;Menghuan1918&apos;s Blog&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;After seeing the approach on that blog, Xnne thought it was a good fit: lightweight, free, and particularly suitable for a technical blog because every comment is managed as a Discussion. Xnne later adopted it and created a custom theme to match the blog&apos;s blue palette.&lt;/p&gt;
&lt;h1&gt;A Custom 404 Page&lt;/h1&gt;
&lt;p&gt;GitHub Pages&apos; default 404 page contains only &lt;code&gt;File not found&lt;/code&gt;, with neither this site&apos;s navigation nor a way back. As soon as visitors reach an address that does not exist, they are abruptly thrown out of the blog&apos;s visual world.&lt;/p&gt;
&lt;p&gt;This site therefore added a custom 404 page. It uses “This part of the knowledge planet is still a desert” to represent coordinates that have not yet been recorded, retains the navigation bar, theme switcher, and footer, and provides two exits: “Back to Home” and “View Archive.” The page continues to use the main site&apos;s theme colors and also adapts to mobile screens and dark mode.&lt;/p&gt;
&lt;p&gt;During the Astro build, a &lt;code&gt;404.html&lt;/code&gt; file is generated at the root. When GitHub Pages cannot find the requested static file, it returns this page while preserving the correct HTTP 404 status. Even when visitors take a wrong turn, they therefore remain on the same knowledge planet.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/img/blog-rebuild-inspirations/Pasted%20image%2020260804223135.png&quot; alt=&quot;The custom 404 page&quot; /&gt;&lt;/p&gt;
&lt;h1&gt;The In-Progress Workbench: Turning Todos into Alchemy&lt;/h1&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/img/blog-rebuild-inspirations/todo-alchemy.jpg&quot; alt=&quot;The In-Progress Workbench using alchemy as its metaphor&quot; /&gt;&lt;/p&gt;
&lt;p&gt;The &lt;a href=&quot;/en/todo/&quot;&gt;In-Progress Workbench&lt;/a&gt; is a public, read-only view of GitHub Issues. GitHub handles creation, editing, permissions, and history, while the blog handles presentation, search, priorities, and browsing by label. Ideas in progress do not have to wait until they become posts or projects before they can be seen.&lt;/p&gt;
&lt;p&gt;Its task-management foundation was inspired by &lt;a href=&quot;https://ticktick.com/&quot;&gt;TickTick&lt;/a&gt;, but Xnne did not want to build yet another ordinary Todo List. The alchemy experiences of &lt;a href=&quot;https://www.potionomics.com/&quot;&gt;Potionomics&lt;/a&gt; and &lt;a href=&quot;https://elderscrolls.bethesda.net/en/skyrim&quot;&gt;The Elder Scrolls V: Skyrim&lt;/a&gt; were therefore folded into the workflow as well: scattered ingredients are gathered, sorted, and placed into the cauldron, eventually becoming something new.&lt;/p&gt;
&lt;p&gt;The site does not reproduce any of those systems wholesale. Instead, it recombines the three inspirations. Items still in progress enter the “Crucible,” organized by priorities from P0 through P3 and by ordinary labels. Closed Issues become “Crystals,” preserving traces of what has been completed. A line on the workbench captures the metaphor:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Mix and refine scattered ideas.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;For Xnne, showing work in progress does more than reveal “what comes next.” It also gives fleeting ideas a container before they disappear. A Todo is no longer merely a line waiting to be crossed out, but material still being refined.&lt;/p&gt;
&lt;h1&gt;A Bilingual Site: Making Another Language Part of the Structure&lt;/h1&gt;
&lt;p&gt;When Xnne first considered adding English to the blog, the task was not simply to “translate the posts.” If English existed only in the article body while navigation, search, archives, statistics, the relationship graph, and RSS still understood only Chinese, the result would have been a scattered collection of translations rather than an English site that could be read on its own.&lt;/p&gt;
&lt;p&gt;The redesign therefore preserves every existing Chinese URL while placing the English site under &lt;code&gt;/en/&lt;/code&gt;, with language changes left to the reader. Pages do not force a redirect based on browser language, and the Chinese and English versions of each post are paired through a stable &lt;code&gt;translationKey&lt;/code&gt;. Old links remain intact, while both languages receive clear and predictable addresses.&lt;/p&gt;
&lt;p&gt;The harder part was carrying language through the entire network of content. The homepage, navigation, archives, series, Bookshelf, In-Progress Workbench, Statistics, relationship graph, search, 404 page, RSS, and SEO all gained English counterparts. WikiLinks, related posts, previous and next navigation, categories, and series are resolved only within the current language. Chinese and English also receive separate search indexes, RSS feeds, statistics catalogs, and graph data, so switching to English does not lead the reader unexpectedly back into Chinese somewhere farther along the path.&lt;/p&gt;
&lt;p&gt;At the same time, all 66 published posts were migrated into complete English counterparts. The migration did not treat them as isolated pieces of text: groups connected by WikiLinks had to move together, or translated links would point toward titles that did not yet exist. Each post first went through translation-pair and file checks, while full production builds were reserved for batch checkpoints. This order kept a large migration divisible, inspectable, and traceable.&lt;/p&gt;
&lt;p&gt;The purpose of making the whole site bilingual was not to pretend that the blog no longer has a linguistic boundary. It was more like laying a second complete path through it. Chinese remains the place where the blog first grew, while English is no longer an attachment beside the body text; it has its own entrances, navigation, and content network. &lt;strong&gt;Bilingualism thus changed from a translation task into part of the blog&apos;s structure itself.&lt;/strong&gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;Those are the main threads of inspiration running through this blog today. Thank you to the creators of these projects, blogs, applications, and games for leaving their practices and imaginations behind, giving those who followed a trail to trace.&lt;/p&gt;
&lt;p&gt;The blog will probably continue to change. The next time a new page grows, this list will gain another tributary.&lt;/p&gt;
</content:encoded></item><item><title>Filled with Empty Things</title><link>https://xnnehang.top/en/posts/man-shi-kong-xu-zhi-wu/</link><guid isPermaLink="true">https://xnnehang.top/en/posts/man-shi-kong-xu-zhi-wu/</guid><description>A cleverly interwoven timeline and a somewhat shallow exploration of death and lifespan.</description><pubDate>Sun, 16 Aug 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;img src=&quot;../../assets/img/covers/man-shi-kong-xu-zhi-wu.jpg&quot; alt=&quot;Filled with Empty Things&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;Parallel timelines?&lt;/h2&gt;
&lt;p&gt;The story’s timeline is somewhat confusing, but a clever narrative weaves it all together. I could not tell whether I was trying to solve a mystery as I read or simply following along; it somewhat forced me to think.&lt;/p&gt;
&lt;p&gt;Overall, it was good. &lt;em&gt;Dreams Come True&lt;/em&gt;, its companion piece, and &lt;em&gt;Mother&lt;/em&gt; all resonated with me. Taken as a whole, however, its themes feel somewhat scattered, and what it has to say about death and lifespan feels faint—or rather, quite shallow.&lt;/p&gt;
&lt;p&gt;That is no exaggeration. The novel and manga versions of &lt;em&gt;Three Days of Happiness&lt;/em&gt;, [[After “A Year for Ten Thousand Yen”]], [[We Who Have No Tomorrow Fell in Love Yesterday]], [[Existentialist Reading Notes]], and [[I Come Alone, I Leave Alone]] have together given my thoughts about death and lifespan something like the effect of thematic reading. By comparison, this work’s discussion remains on the surface for me. Perhaps manga as a medium lacks some of the complexity that prose can provide.&lt;/p&gt;
&lt;p&gt;Still, as the first book I have finished in one sitting in quite a while, it was a good start.&lt;/p&gt;
</content:encoded></item><item><title>The Lychee of Chang&apos;an</title><link>https://xnnehang.top/en/posts/changan-de-lizhi/</link><guid isPermaLink="true">https://xnnehang.top/en/posts/changan-de-lizhi/</guid><description>Devoting yourself to something over the long term—even if it is an impractical dream—is a pretty good choice.</description><pubDate>Sat, 08 Aug 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;img src=&quot;../../assets/img/changan-de-lizhi/PixPin_2026-08-08_23-12-52.jpg&quot; alt=&quot;The Lychee of Chang&apos;an&quot; /&gt;&lt;/p&gt;
&lt;p&gt;An interesting perspective.&lt;/p&gt;
&lt;p&gt;Interesting characters.&lt;/p&gt;
&lt;p&gt;It reminded me of just how poor arithmetic was in medieval Europe—so poor that its scholars might not even have been able to solve the classic chickens-and-rabbits problem. Under the constraints imposed by theology, the ingenious reasoning and calculations behind heliocentrism were genuinely impressive, but they were less mathematics than mathematical intuition.&lt;/p&gt;
&lt;p&gt;By contrast, quite a few people in ancient China were remarkably good at arithmetic, even though it received little recognition at the time. The Daoist writings of that era are truly astonishing as well.&lt;/p&gt;
&lt;p&gt;That is why it is worth having something to pursue, even if that pursuit is immortality. Or perhaps the path endorsed by the mainstream of an age may later prove neither useful nor even correct.&lt;/p&gt;
&lt;p&gt;Better, then, to find something you love and pursue it over the long term, even if it is as impractical as a dream.&lt;/p&gt;
</content:encoded></item><item><title>First Impressions of GitHub Stacked PRs</title><link>https://xnnehang.top/en/posts/github-stacked-prs/</link><guid isPermaLink="true">https://xnnehang.top/en/posts/github-stacked-prs/</guid><description>Notes from a real refactoring project on GitHub Stacked PRs: linear dependencies, layered merging, multi-level synchronization, and local branch relationships.</description><pubDate>Wed, 05 Aug 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;img src=&quot;../../assets/img/github-stacked-prs/cover.jpg&quot; alt=&quot;Article cover&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Today I noticed that GitHub has opened Stacked PRs as a Public Preview. It is no longer something that requires joining a waitlist before trying it.&lt;/p&gt;
&lt;p&gt;I happened to have a very old PyQT Pomodoro project that I have recently wanted to refactor into Tauri + Rust, so I decided to try it out first.&lt;/p&gt;
&lt;h2&gt;What Is &lt;code&gt;gh stack&lt;/code&gt;?&lt;/h2&gt;
&lt;p&gt;It is a little like a &lt;code&gt;gh&lt;/code&gt; CLI extension. It lets pull requests be connected in an orderly way instead of existing independently and merely mentioning one another like sworn brothers.&lt;/p&gt;
&lt;p&gt;It lets PRs stack on feature branches rather than all pointing directly to the &lt;code&gt;main&lt;/code&gt; branch.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/img/github-stacked-prs/stack-overview.jpg&quot; alt=&quot;Overview of a Stacked PR relationship&quot; /&gt;&lt;/p&gt;
&lt;h3&gt;What Does It Bring?&lt;/h3&gt;
&lt;p&gt;This is what I wrote before:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Large PRs are hard to review, take a long time to move through the process, and make conflicts and blocking relationships difficult to understand. They require frequent rebasing.

Small PRs are fast to review, but their relationships can only be connected through mentions. Everything becomes fragmented and unclear. I am used to opening atomic PRs, so I often run into this problem and lose track of what has been done.

`gh stack` can combine the advantages of both approaches while making collaboration more atomic.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;No more preamble. Let us begin.&lt;/p&gt;
&lt;h3&gt;How Do You Create One?&lt;/h3&gt;
&lt;p&gt;For the exact steps, see &lt;a href=&quot;https://docs.github.com/en/pull-requests/how-tos/create-pull-requests/creating-stacked-pull-requests&quot;&gt;Creating stacked pull requests&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;But if you rely on tools such as Claude Code or Codex, GitHub also provides a corresponding Skill installation. It is somewhat like the Skill injection work memU has been doing recently.&lt;/p&gt;
&lt;p&gt;You can simply tell Codex or Claude to globally install GitHub’s new &lt;code&gt;gh stack&lt;/code&gt; and its Skill for you.&lt;/p&gt;
&lt;p&gt;In other words, we do not need to care about which commands to type; we can stay at the higher-level view.&lt;/p&gt;
&lt;p&gt;Even if we do not care about the mechanics, though, we still need to understand its shape and its benefits.&lt;/p&gt;
&lt;h2&gt;Stacked PRs from a Maintainer’s Perspective&lt;/h2&gt;
&lt;h3&gt;Can They Be Merged in Order?&lt;/h3&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/img/github-stacked-prs/merge-single-pr.jpg&quot; alt=&quot;Merge a bottom PR independently&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/img/github-stacked-prs/merge-stack.png&quot; alt=&quot;Merge multiple Stack layers at once&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Yes—and they can only be merged in order.&lt;/p&gt;
&lt;p&gt;As shown here, the bottom PR can be merged one by one. Once it is merged, as long as there are no conflicts, GitHub automatically cascades a rebase across the remaining upper branches on the server and force-pushes updates to the remote PRs. Developers do not need to manually run &lt;code&gt;gh stack sync&lt;/code&gt;; the automated process stops only when it encounters a conflict and needs developer intervention.&lt;/p&gt;
&lt;p&gt;But merging an upper PR also merges all the PRs below it. If my cursor is on the third layer, merging it merges three PRs at once.&lt;/p&gt;
&lt;h3&gt;Incremental Reviews&lt;/h3&gt;
&lt;p&gt;Using the diagram above as an example, #23 contains all of #23’s code.&lt;/p&gt;
&lt;p&gt;And #24 contains all of #23’s code plus #24’s incremental code, but review shows only the diff between #24 and #23.&lt;/p&gt;
&lt;p&gt;All reviews are incremental; they do not overlap.&lt;/p&gt;
&lt;h2&gt;Stacked PRs from a Contributor’s Perspective&lt;/h2&gt;
&lt;h3&gt;An Immediate Reality Check&lt;/h3&gt;
&lt;p&gt;All branches in a Stack PR must be in the same repository, and that repository must also contain the branch they will merge into.&lt;/p&gt;
&lt;p&gt;For example:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;xnne-bot wants to merge 4 commits into NevaMind-AI:main
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If I open a PR from a fork to upstream, my PRs cannot form a Stack. They can only be merged together when they all live in the &lt;code&gt;nevamind-AI/memU&lt;/code&gt; repository.&lt;/p&gt;
&lt;p&gt;At least for now.&lt;/p&gt;
&lt;h3&gt;Are Tree-Shaped Stacks Supported?&lt;/h3&gt;
&lt;p&gt;The official example looks roughly like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;L0 main
L1  └── auth-layer
L2     └── api-endpoints
L3         └── frontend
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It is a linear set of layers.&lt;/p&gt;
&lt;p&gt;My first thought was: could it be a tree instead of a stack?&lt;/p&gt;
&lt;p&gt;At present, the answer is no. Every PR must follow a strict dependency relationship. For an upper PR to merge, the lower PRs must merge with it.&lt;/p&gt;
&lt;p&gt;What happens if two PRs are at the same level?&lt;/p&gt;
&lt;p&gt;:::note[Opus]
Two PRs cannot exist as the “same layer” of one Stack.&lt;/p&gt;
&lt;p&gt;Suppose PR B and PR C both use PR A’s branch as their base. From Git’s and ordinary PRs’ perspective, this is entirely valid, but they become two sibling PRs rather than part of the same linear Stack. Merging one will not merge the other.&lt;/p&gt;
&lt;p&gt;If B and C depend on one another in sequence, arrange them as &lt;code&gt;A → B → C&lt;/code&gt;. If they are independent and merely share A as a dependency, it is better to merge their common foundation A first, then let B and C each begin from the new trunk.&lt;/p&gt;
&lt;p&gt;In short, a Stack requires each layer to have a unique layer above and below it. Once a same-level branch appears, it is no longer a Stack but an ordinary branch dependency graph.
:::&lt;/p&gt;
&lt;p&gt;That is to say, a Stack should not contain parallel relationships. It exists solely to handle linear, inclusive dependencies. If a parallel relationship exists, the Stack should break at that point.&lt;/p&gt;
&lt;p&gt;Break one PR down progressively and incrementally.&lt;/p&gt;
&lt;h3&gt;Do Upper PRs Include All Lower-Level Code, and Do They Change in Real Time?&lt;/h3&gt;
&lt;p&gt;If it were only a simple puzzle, ordinary mentions could already handle it.&lt;/p&gt;
&lt;p&gt;But the most frustrating part of mentions is this: if PR B contains all of PR A’s code and depends on PR A, then whenever PR A changes, we must manually align PR B with it.&lt;/p&gt;
&lt;p&gt;That is also why we often hesitate to split a PR, only for it to become very large in the end.&lt;/p&gt;
&lt;p&gt;A Stack solves this problem. Because an upper PR includes all lower PR content, any change to a lower PR will &lt;s&gt;automatically synchronize upward&lt;/s&gt;. The whole thing feels like one PR, but it is reviewed as different parts.&lt;/p&gt;
&lt;p&gt;:::note[Opus]
&lt;strong&gt;The triggering scenarios need to be distinguished here: upper branches really do contain lower-level code, and GitHub does automatically synchronize the remaining branches after a lower Stack PR is merged. But if you merely add and push a commit to a lower branch, that change does not immediately propagate to upper branches.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Suppose we split a refactor into five layers:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;main
└── PR A: data model
    └── PR B: core service
        └── PR C: API
            └── PR D: frontend interface
                └── PR E: integration tests
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;These branches form one continuous chain in Git history:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;main ← A0 ← B0 ← C0 ← D0 ← E0
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;E’s branch therefore does contain the code from A, B, C, and D. But because each PR uses the branch immediately below it as its base, GitHub normally shows only E’s test changes when you view PR E, rather than showing all four preceding layers of diff again.&lt;/p&gt;
&lt;p&gt;Now suppose the bottom PR, A, receives an additional commit &lt;code&gt;A1&lt;/code&gt; that is pushed to the remote but has not yet been merged. A’s branch moves forward, but B through E do not move with that ordinary push in real time. They temporarily diverge into this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;main
└── A0
    ├── A1                         ← PR A’s new position
    └── B0 ← C0 ← D0 ← E0         ← The four upper layers remain on the old chain
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Without Stacked PRs, we would have to manually align the four layers in sequence:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Rebase B onto A1
Rebase C onto the new B
Rebase D onto the new C
Rebase E onto the new D
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;gh stack&lt;/code&gt; knows the entire dependency chain, so from A’s layer you can run:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;gh stack rebase --upstack
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It performs a cascading rebase and eventually produces:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;main ← A0 ← A1 ← B1 ← C1 ← D1 ← E1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here, &lt;code&gt;B1&lt;/code&gt; through &lt;code&gt;E1&lt;/code&gt; are the new commits created by rebasing. Even if the code at a given layer has not changed substantially, its commit SHA is rewritten. For this &lt;strong&gt;not-yet-merged case, where only a lower branch has been modified and pushed&lt;/strong&gt;, you can run &lt;code&gt;gh stack rebase --upstack&lt;/code&gt; locally and then &lt;code&gt;gh stack push&lt;/code&gt;, or simply run:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;gh stack sync
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;sync&lt;/code&gt; fetches, cascades a rebase across the entire Stack, pushes it, and synchronizes the PR and Stack state on GitHub. Under normal circumstances, whether there are two upper layers or ten, the developer runs the same command: &lt;strong&gt;the number of layers does not increase the number of steps linearly&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;But the situation differs if the lower PR has already been merged through GitHub Stack merge. GitHub then cascades a rebase from bottom to top across the remaining branches on the server and automatically force-pushes updates to the remote PRs. Without conflicts, this requires no manual &lt;code&gt;sync&lt;/code&gt;; you only run &lt;code&gt;gh stack sync&lt;/code&gt; later when your local state needs to catch up with the remote. The &lt;strong&gt;Rebase Stack&lt;/strong&gt; button on GitHub’s page is the same kind of server-side cascading rebase, except that it must be clicked manually.&lt;/p&gt;
&lt;p&gt;If the change occurs in the middle PR C, A and B do not need to change. Only D and E need to realign from C. Run &lt;code&gt;gh stack rebase --upstack&lt;/code&gt; on C’s branch:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;main ← A ← B ← C1 ← D1 ← E1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;What can truly become troublesome is &lt;strong&gt;conflicts, not synchronization itself&lt;/strong&gt;. Whether using a local cascading rebase or GitHub’s server-side cascade after a merge, the normal path can process the entire Stack in one action; manual intervention is needed only when conflicts occur.&lt;/p&gt;
&lt;p&gt;If &lt;code&gt;gh stack sync&lt;/code&gt; encounters a rebase conflict locally, it restores each branch to its previous state and tells you to use &lt;code&gt;gh stack rebase&lt;/code&gt; instead. After resolving the current conflict and staging the files, run &lt;code&gt;gh stack rebase --continue&lt;/code&gt;. If later layers conflict too, continue resolving them. GitHub’s server-side rebase cannot resolve conflicts on your behalf either, so you must return to local development.&lt;/p&gt;
&lt;p&gt;Additionally, a rebase rewrites every affected upper branch, so remote PRs need updating and CI may run again. If the repository has protections such as “dismiss approval when new commits are pushed,” existing review status can also be affected. These costs become more obvious the deeper the Stack is and the more each layer edits the same code.&lt;/p&gt;
&lt;p&gt;So Stacked PRs &lt;strong&gt;really do reduce layer-by-layer alignment to an automatic cascading operation&lt;/strong&gt;: after a lower PR is merged, GitHub automatically rebases and force-pushes the remote Stack; when an unmerged lower branch changes, you actively trigger it with a local &lt;code&gt;rebase + push&lt;/code&gt;, &lt;code&gt;sync&lt;/code&gt;, or the web UI’s &lt;strong&gt;Rebase Stack&lt;/strong&gt;. Under normal circumstances you do not need to operate layer by layer; human intervention is needed only for conflicts. In practice, each layer should still stay focused and cross-layer edits to the same area should be minimized.
:::&lt;/p&gt;
&lt;p&gt;That is very clear: &lt;strong&gt;GitHub automatically completes remote synchronization after a lower PR is merged&lt;/strong&gt;, stopping only for conflicts. &lt;code&gt;sync&lt;/code&gt; is mainly for actively realigning unmerged changes or bringing local state up to date with the remote; it is not something you must run after every merge.&lt;/p&gt;
&lt;p&gt;:::warning[Automatic Remote Synchronization Does Not Mean Automatic Local Synchronization]
GitHub’s automatic cascading rebase and force-push update &lt;strong&gt;remote branches&lt;/strong&gt;. The local branches on a developer’s computer are not rewritten in reverse by the remote repository. Once the remote Stack updates automatically, local branches remain at their old commit SHAs; before continuing work, run &lt;code&gt;gh stack sync&lt;/code&gt;, or at least &lt;code&gt;git fetch&lt;/code&gt;, to obtain the latest remote state.&lt;/p&gt;
&lt;p&gt;If you skip this step, local and remote state diverge and later rebases may conflict. &lt;code&gt;gh stack push&lt;/code&gt; uses &lt;code&gt;--force-with-lease&lt;/code&gt;, so it normally refuses to push when the remote has changed instead of overwriting it outright. But manually running the unsafe &lt;code&gt;git push --force&lt;/code&gt; can overwrite the result of GitHub’s automatic rebase.&lt;/p&gt;
&lt;p&gt;The more accurate workflow is therefore: &lt;strong&gt;GitHub automatically updates the remote Stack; before continuing to modify or push, local development must fetch or synchronize the remote state.&lt;/strong&gt; If there are already new local changes, commit or stash them before synchronizing the remote.
:::&lt;/p&gt;
&lt;h3&gt;What Do Local Branches Look Like During &lt;code&gt;sync&lt;/code&gt;?&lt;/h3&gt;
&lt;p&gt;The previous section explained that upper PRs contain all lower PR code and that lower changes are synchronized with &lt;code&gt;sync&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;From the perspective of local branches, do all branches move together? Do branches include all code? How are the diffs between branches ultimately turned into the incremental diffs we review in PRs? Do Stack-linked branches carry any special marker or relationship?&lt;/p&gt;
&lt;p&gt;:::note[Opus]
&lt;strong&gt;Conclusion: upper branches include lower-level code; &lt;code&gt;sync&lt;/code&gt; moves only the branches that need realignment; Stack relationships are not a special Git capability.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Suppose there are four local layers:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;main ← A ← B ← C ← D
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;Checking out A includes &lt;code&gt;main + A&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Checking out C includes &lt;code&gt;main + A + B + C&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Checking out D includes the entire chain’s code.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If A changes, then after running &lt;code&gt;gh stack sync&lt;/code&gt;, B, C, and D are cascaded and rebased, so their branch pointers and commit SHAs update accordingly. If only C changes, normally only C and D need updating. It changes branch pointers; it does not modify the same working directory’s files multiple times.&lt;/p&gt;
&lt;p&gt;Each PR shows only its own layer because it compares itself with the branch immediately below it:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;PR A: main → A
PR B: A → B
PR C: B → C
PR D: C → D
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So even though D contains the code from A, B, and C, PR D still displays only the incremental &lt;code&gt;C..D&lt;/code&gt; diff.&lt;/p&gt;
&lt;p&gt;To Git, these are still ordinary branches with no special Stack marker. The relationship is recorded mainly in two places:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Each PR’s base/head relationship;&lt;/li&gt;
&lt;li&gt;GitHub’s Stack metadata for presentation and management.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;code&gt;gh stack init&lt;/code&gt; also maintains local hierarchy information; &lt;code&gt;gh stack link&lt;/code&gt; can instead link existing PRs into a GitHub Stack in sequence without using that local tracking state.
:::&lt;/p&gt;
&lt;p&gt;All right, I understand. So during &lt;code&gt;sync&lt;/code&gt;, the same file is not modified N times just because there are N layers. Rather, each file should change only once, and the heads of the other branches then point to the updated file.&lt;/p&gt;
&lt;p&gt;Seen this way, GitHub Stack seems rather straightforward to implement. It only needs to know the base of each PR branch.&lt;/p&gt;
</content:encoded></item><item><title>The Shape of a Protocol Determines Its Capabilities: Why Codex Removed chat_completion, and What Actually Blocks a Desktop Companion from Talking While It Works</title><link>https://xnnehang.top/en/posts/resposne-vs-chat_completion/</link><guid isPermaLink="true">https://xnnehang.top/en/posts/resposne-vs-chat_completion/</guid><description>From Codex&apos;s hard removal of chat/completions to the migration damage it caused in new-api, this examines the real tool-flow differences between Anthropic Messages and OpenAI protocols—why my long-chain silence is not the protocol&apos;s fault, and what truly counts as talking while working.</description><pubDate>Tue, 28 Jul 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;img src=&quot;../../assets/img/covers/18409210202869120.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;Preface&lt;/h2&gt;
&lt;p&gt;Today, let us talk a little about transport protocols.&lt;/p&gt;
&lt;p&gt;The common ones are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Chat Completion&lt;/code&gt;: /v1/chat/completions&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Responses&lt;/code&gt;: /v1/responses&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Claude Response&lt;/code&gt;: /v1/messages&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;code&gt;XnneHangLab&lt;/code&gt; has always used &lt;code&gt;chat_completion&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The reason is simple: &lt;code&gt;chat_completion&lt;/code&gt; is what normal users and I encounter. Early versions of newapi did not support Responses; it seems support only arrived in versions released after May this year. Platforms such as DeepSeek also expose only the Completion endpoint, which is rather unfortunate. When I wanted to find a proper Responses endpoint to test a newer codex-cli, I could not find one.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;P.S. In everyday use, the recent ds-v4-flash has already shown Doubao-like low intelligence and a tendency for its two halves to argue with each other. Even simple instructions need several attempts. I am already planning to replace it completely with grok-4.5 for the assistance work in Obsidian-YOLO.&amp;lt;br&amp;gt;
I do not know whether it has been dumbed down, but for me the easiest way to judge a model&apos;s intelligence is to have it review code. Compared with gpt-5.6-sol and grok-4.5, deepseek-v4-flash code reviews belong to the group that makes you want to drool. Its multi-step reasoning and deep thinking are a mess, and it considers things far too narrowly.&amp;lt;br&amp;gt;
The only thing worth praising is DeepSeek&apos;s post-training, which makes it sound more human. It can only really be used for role-playing conversations. But when will image understanding finally arrive in the API? The web client has had it for more than a month already.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I wanted to investigate this because, while testing memu-cli integration with codex-cli, I found that newer versions (&amp;gt;0.95) had directly removed &lt;code&gt;Chat Completion&lt;/code&gt; and moved to &lt;code&gt;Response&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;Questions to Discuss&lt;/h2&gt;
&lt;h3&gt;The Difference Between chat_completion and responses, and the Value of Migrating&lt;/h3&gt;
&lt;p&gt;Let us look at why codex-cli did this—perhaps beginning with issues in the official Codex repository.&lt;/p&gt;
&lt;p&gt;And distinguish the main differences and the value of migrating: what benefits, if any, would it bring to XnneHangLab?&lt;/p&gt;
&lt;h3&gt;The Difference Between Anthropic Messages and OpenAI&apos;s Streaming Tool Responses&lt;/h3&gt;
&lt;p&gt;And let us recall a question I left in an earlier ramble:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Can we investigate why the Anthropic protocol supports alternating tool tokens and chat tokens, while OpenAI can only do tools first and chat afterward, yet prompt injection seems able to make it announce the tool it will execute?

Does it have the complete tool schema when it announces this? In which LLM call does that announcement happen?
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This may not be precise enough. The scenario was this:&lt;/p&gt;
&lt;p&gt;Once we added ToolCall to a desktop-companion setting, a ToolCall not only brought an extra LLM call, but often took a while to execute. The tool result then had to be sent back to the LLM for a reply. Perceptually, that added five or six seconds of response latency, and the model appeared unusually &lt;code&gt;silent&lt;/code&gt; during it.&lt;/p&gt;
&lt;p&gt;At the time, I added a policy-level prompt-injection plugin: &lt;a href=&quot;https://github.com/XnneHangLab/XnneHangLab/blob/dev/src/lab/plugins/pre_tool_preview/plugin.toml&quot;&gt;pre_tool_preview&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;It roughly tells the model: if you are about to execute a tool, verbally announce what you are going to do first.&lt;/p&gt;
&lt;p&gt;Afterward, the model did indeed give short previews such as &lt;code&gt;Let me take a screenshot and see what you are doing?&lt;/code&gt; and &lt;code&gt;Let me look through your recent diary entries&lt;/code&gt; before doing things.&lt;/p&gt;
&lt;p&gt;The overall effect was good. It softened the deathlike silence that had been there before.&lt;/p&gt;
&lt;h3&gt;Why Does My pre_tool_preview Work? What Are Its Limits?&lt;/h3&gt;
&lt;p&gt;I have partly forgotten the exact implementation and need to verify it again. I also need a token-level &lt;code&gt;streaming token&lt;/code&gt; demonstration: how the tokens are ordered, whether the preview occurs before or after tool tokens, why it can preview, then execute, then answer, and how many LLM Tool Calls lie in between.&lt;/p&gt;
&lt;p&gt;How many times can it preview? Does it support staged previews in a long tool-call chain?&lt;/p&gt;
&lt;p&gt;If I migrate to Responses, will this feature carry over? Will Responses change the returned token stream?&lt;/p&gt;
&lt;p&gt;My roommate also says Responses supports long connections. Is that true? Could it remove the first-token delay caused by handshakes in desktop-companion conversations?&lt;/p&gt;
&lt;p&gt;And why did I once say Anthropic supports talking while working while OpenAI does not? What is different about their streaming token flows?&lt;/p&gt;
&lt;h3&gt;How Can an Agent Talk While Working in Engineering Terms?&lt;/h3&gt;
&lt;p&gt;We know that pre_tool_preview is probably only the most basic approach.&lt;/p&gt;
&lt;p&gt;In engineering practice, some Agents support long ToolCall chains, such as &lt;a href=&quot;https://github.com/Lapis0x0/obsidian-yolo&quot;&gt;Obsidian-yolo&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;This seems to involve high-frequency ToolCalls and feedback. How are their prompts written? How do they get the model to support long chained exchanges? It appears to contradict my earliest understanding of chat_completion, because there seem to be no repeated handshakes in the middle.&lt;/p&gt;
&lt;p&gt;When do repeated handshakes mostly happen?&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;Those are roughly the questions. Next, let us ask Teacher Fable or Teacher Opus. Please do not answer only from your own knowledge; many of these details need evidence. Ideally, use issues from the codex or newapi repositories and documentation from Anthropic and OpenAI.&lt;/p&gt;
&lt;h2&gt;Why codex-cli Removed Chat Completions&lt;/h2&gt;
&lt;p&gt;Why did codex-cli remove chat_completion?&lt;/p&gt;
&lt;p&gt;I had always used it without issue. Codex-cli directly removed support for the protocol, and the benefit looked substantial.&lt;/p&gt;
&lt;p&gt;Codex itself is open source. This question requires not only comparing the protocols, but more importantly tracking community issues, discussions, and pull requests—as well as related issues and PRs in the newapi community.&lt;/p&gt;
&lt;p&gt;I need to understand the full process from beginning to end. Why was the decision made? Was it unilateral or community-driven? How much community support did it have?&lt;/p&gt;
&lt;p&gt;:::note[Opus]
&lt;strong&gt;Conclusion: this was a protocol shutdown with an announcement, a deprecation period, and a hard-removal PR. It was executed unilaterally, with zero community support. The stated reason was maintenance cost; the real reason was that Codex&apos;s new feature primitives only fit in Responses. Your “&amp;gt;0.95” is as precise as it gets—it was &lt;code&gt;rust-v0.95.0&lt;/code&gt;.&lt;/strong&gt;&lt;/p&gt;
&lt;h3&gt;Timeline&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Date&lt;/th&gt;
&lt;th&gt;Event&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;2025-12-09&lt;/td&gt;
&lt;td&gt;Official deprecation announcement: &lt;a href=&quot;https://github.com/openai/codex/discussions/7782&quot;&gt;codex#7782&lt;/a&gt; (&lt;code&gt;etraut-openai&lt;/code&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2025-12-11&lt;/td&gt;
&lt;td&gt;Runtime warning added for &lt;code&gt;wire_api = &quot;chat&quot;&lt;/code&gt;: &lt;a href=&quot;https://github.com/openai/codex/pull/7897&quot;&gt;codex#7897&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2026-02-03&lt;/td&gt;
&lt;td&gt;Hard-removal PR: &lt;strong&gt;&lt;code&gt;chore: nuke chat/completions API&lt;/code&gt;&lt;/strong&gt;, &lt;a href=&quot;https://github.com/openai/codex/pull/10157&quot;&gt;codex#10157&lt;/a&gt;, 49 files, +268/−2931&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2026-02-04&lt;/td&gt;
&lt;td&gt;First release containing that commit: &lt;strong&gt;&lt;code&gt;rust-v0.95.0&lt;/code&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The compare API confirms that &lt;code&gt;d2394a24...rust-v0.95.0&lt;/code&gt; is &lt;code&gt;ahead&lt;/code&gt;, while &lt;code&gt;...rust-v0.94.0&lt;/code&gt; is &lt;code&gt;diverged&lt;/code&gt;. &lt;strong&gt;0.94 could still use chat; starting with 0.95, it could not.&lt;/strong&gt;&lt;/p&gt;
&lt;h3&gt;Unilateral or Community Decision?&lt;/h3&gt;
&lt;p&gt;The announcement&apos;s reaction distribution was &lt;strong&gt;👎 85 / 😕 10 / 🚀 2 / 👍 0&lt;/strong&gt;, with 21 upvotes and 11 comments. It was categorized as &lt;code&gt;General&lt;/code&gt;, not a poll, and had no selected answer. The wording was not consultative: “the Codex team &lt;strong&gt;is&lt;/strong&gt; deprecating” and “Full removal &lt;strong&gt;is slated for&lt;/strong&gt; early February 2026.” The removal PR had an empty body, zero review comments, and merged in five days. Afterwards, &lt;a href=&quot;https://github.com/openai/codex/issues/31083&quot;&gt;codex#31083&lt;/a&gt; proposed restoring the option with a feature flag; it received zero reactions and no response.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Zero likes and eighty-five dislikes, and it proceeded anyway.&lt;/strong&gt; But do not rush to criticize—the announcement&apos;s disclaimer explains everything:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;The vast majority of Codex users are unaffected by this change.&lt;/strong&gt; If you are using OpenAI-hosted models with a default Codex configuration, you are already using the &lt;code&gt;responses&lt;/code&gt; API.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;The people voting and the people paying are not the same group.&lt;/strong&gt; Those eighty-five dislikes mostly came from local-model and third-party gateway users. The lesson for you is this: Codex being open source does not mean it promises protocol compatibility. &lt;strong&gt;“Upstream can unilaterally delete an entire protocol path at any time” should be a design assumption.&lt;/strong&gt;&lt;/p&gt;
&lt;h3&gt;Official Reason vs. the Real Reason&lt;/h3&gt;
&lt;p&gt;The announcement cites maintenance cost:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;the &lt;code&gt;chat/completions&lt;/code&gt; API has &lt;strong&gt;increasingly hampered our ability to improve Codex&lt;/strong&gt;... added complexity, introduced regressions, and increased support overhead.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;But the harder reason is expressive power. &lt;strong&gt;Chat is message-centered&lt;/strong&gt;—everything is forced into &lt;code&gt;role&lt;/code&gt;, &lt;code&gt;content&lt;/code&gt;, and &lt;code&gt;tool_calls&lt;/code&gt;—while &lt;strong&gt;Responses is item-centered&lt;/strong&gt;: an ordered list of parallel items, where &lt;code&gt;reasoning&lt;/code&gt;, &lt;code&gt;function_call&lt;/code&gt;, &lt;code&gt;message&lt;/code&gt;, and &lt;code&gt;web_search_call&lt;/code&gt; are independent, first-class entries. Later additions to Codex simply have nowhere to go in chat: &lt;code&gt;agent_message&lt;/code&gt; (&lt;a href=&quot;https://github.com/openai/codex/issues/33551&quot;&gt;#33551&lt;/a&gt;), MCP tools with &lt;code&gt;type: &quot;namespace&quot;&lt;/code&gt; (&lt;a href=&quot;https://github.com/openai/codex/issues/23186&quot;&gt;#23186&lt;/a&gt;), and encrypted task delegation (&lt;a href=&quot;https://github.com/openai/codex/issues/34833&quot;&gt;#34833&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;The most candid evidence is the current &lt;code&gt;WireApi&lt;/code&gt; enum: &lt;strong&gt;only one member remains&lt;/strong&gt;. The configuration option survives, but it no longer represents a choice:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&quot;WireApi&quot;: {
  &quot;oneOf&quot;: [{ &quot;enum&quot;: [&quot;responses&quot;], &quot;type&quot;: &quot;string&quot; }]
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;a href=&quot;https://developers.openai.com/api/docs/guides/migrate-to-responses&quot;&gt;official migration documentation&lt;/a&gt; claims the following benefits—&lt;strong&gt;self-reported, without third-party reproduction&lt;/strong&gt;: +3% on SWE-bench, &lt;strong&gt;40%–80% better cache utilization&lt;/strong&gt;, &lt;code&gt;store: true&lt;/code&gt; preserving reasoning across turns, and optional encrypted reasoning. The cache point is important: Codex has the classic long-context, repeated-prefix workload, so a cache hit directly becomes money.&lt;/p&gt;
&lt;h3&gt;What Happened to new-api&lt;/h3&gt;
&lt;p&gt;(First, filter out noise: all those new-api PRs prefixed &lt;code&gt;[codex]&lt;/code&gt; are maintainers &lt;strong&gt;using Codex to write code&lt;/strong&gt;, not compatibility work.)&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Category&lt;/th&gt;
&lt;th&gt;Evidence&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Cache passthrough broke&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;a href=&quot;https://github.com/QuantumNous/new-api/issues/3389&quot;&gt;#3389&lt;/a&gt; measured direct versus proxied calls: uncached input was &lt;strong&gt;11.74x&lt;/strong&gt;, cached input fell to only &lt;strong&gt;9.16%&lt;/strong&gt;, and output was only 43.87%; &lt;a href=&quot;https://github.com/QuantumNous/new-api/issues/3309&quot;&gt;#3309&lt;/a&gt; could not recognize cache fields in nonstandard positions.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;New encrypted-reasoning errors&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;a href=&quot;https://github.com/QuantumNous/new-api/issues/3240&quot;&gt;#3240&lt;/a&gt;: &lt;code&gt;invalid_encrypted_content&lt;/code&gt;; channel affinity through &lt;code&gt;prompt_cache_key&lt;/code&gt; was insufficient, and LiteLLM&apos;s &lt;code&gt;encrypted_content_affinity&lt;/code&gt; was needed. &lt;strong&gt;Still open.&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Lossy fallback channels&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;a href=&quot;https://github.com/QuantumNous/new-api/pull/5209&quot;&gt;#5209&lt;/a&gt; was the “support only arrived around May” change you remembered. But it drops MCP tools (&lt;a href=&quot;https://github.com/QuantumNous/new-api/issues/5938&quot;&gt;#5938&lt;/a&gt;), &lt;code&gt;reasoning_content&lt;/code&gt; (&lt;a href=&quot;https://github.com/QuantumNous/new-api/issues/6396&quot;&gt;#6396&lt;/a&gt;), reasoning summaries (&lt;a href=&quot;https://github.com/QuantumNous/new-api/pull/6449&quot;&gt;#6449&lt;/a&gt;), and &lt;code&gt;include_usage&lt;/code&gt; (&lt;a href=&quot;https://github.com/QuantumNous/new-api/issues/6149&quot;&gt;#6149&lt;/a&gt;).&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Engineering debris&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;SSE without &lt;code&gt;Content-Type&lt;/code&gt; (&lt;a href=&quot;https://github.com/QuantumNous/new-api/issues/6075&quot;&gt;#6075&lt;/a&gt;), zstd decompression (&lt;a href=&quot;https://github.com/QuantumNous/new-api/issues/6313&quot;&gt;#6313&lt;/a&gt;), OOM (&lt;a href=&quot;https://github.com/QuantumNous/new-api/issues/5698&quot;&gt;#5698&lt;/a&gt;), channel affinity blocking failover (&lt;a href=&quot;https://github.com/QuantumNous/new-api/issues/4541&quot;&gt;#4541&lt;/a&gt;), and private endpoint &lt;code&gt;/v1/alpha/search&lt;/code&gt; (&lt;a href=&quot;https://github.com/QuantumNous/new-api/issues/6114&quot;&gt;#6114&lt;/a&gt;).&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Two important points. First, &lt;strong&gt;encrypted reasoning makes load balancing stateful&lt;/strong&gt;: the context now contains an owned, non-movable blob, which did not exist in the chat era. Second, and more importantly for you:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Fallback channels lose exactly the reasoning and tool metadata you want to observe in later token flows.&lt;/strong&gt; Before demonstrating streaming tokens, verify whether you are using a native Responses upstream or newapi&apos;s fallback channel. Otherwise, the alternation you see is gateway-translated, not the model&apos;s actual output.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Most of these issues remain &lt;strong&gt;open&lt;/strong&gt;. It is not that newapi is not trying; &lt;code&gt;/v1/responses&lt;/code&gt; has a surface area an order of magnitude larger than &lt;code&gt;/v1/chat/completions&lt;/code&gt;: state, encryption, item ordering, lifecycle events, and private endpoints all need reimplementation.&lt;/p&gt;
&lt;h3&gt;One-Sentence Version&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Officially, legacy support slows development; in the code, only Responses can contain the new features; commercially, affected users are not paying customers. Three statements, one irreversible action. For XnneHangLab, the question is not whether to migrate: the gateway has already migrated half of it for you, and it loses exactly the information you most want to investigate while translating.&lt;/strong&gt;
:::&lt;/p&gt;
&lt;h3&gt;A Summary and Another Complaint About OpenAI&lt;/h3&gt;
&lt;p&gt;Okay, then this part is clear.&lt;/p&gt;
&lt;p&gt;OpenAI simply did not want to maintain two sets of logic in Codex (&lt;code&gt;chat_completion&lt;/code&gt; and &lt;code&gt;responses&lt;/code&gt;), so it unilaterally removed the &lt;code&gt;chat&lt;/code&gt; interface for more agile development and faster iteration. It cut off the people who do not directly pay OpenAI—the users of third-party model providers—and was criticized by the community for a long time.&lt;/p&gt;
&lt;p&gt;But it also seems internally contradictory. It removed &lt;code&gt;chat_completion&lt;/code&gt;, then recently merged the ChatGPT and Codex clients into an architecture like Claude Desktop.&lt;/p&gt;
&lt;p&gt;Earlier, we discussed [[Learning from Bad Architecture: What Claude Desktop&apos;s Five Scheduling Systems Reveal About Separating Cowork and Code]]. This architecture makes maintenance costs rise geometrically; separate maintenance is much better than merging everything together. Recently, during host adaptation for memU, both Claude Desktop and Codex Desktop showed terrible adaptability because of the strange sandboxes and low shell permissions of their Cowork and Chat modes.&lt;/p&gt;
&lt;p&gt;The first move looks like a pursuit of technical cleanliness, and the next turns the architecture into a pile of mess. (Perhaps the code is not all maintained in the official Codex repository; maybe the core is maintained separately, like Claude Code, with the desktop client separate.)&lt;/p&gt;
&lt;p&gt;It is probably all driven by commercialization, yet I do not understand the pursuit or the decisions.&lt;/p&gt;
&lt;p&gt;OpenAI is always like this: it likes doing two things at once instead of doing one thing well. While updating GPT models, it splits off &lt;code&gt;codex&lt;/code&gt; models, then &lt;code&gt;o1&lt;/code&gt;, &lt;code&gt;o2&lt;/code&gt;, and &lt;code&gt;o3&lt;/code&gt;; later it throws away Codex and focuses only on GPT. The naming is also chaotic, as if it names things whenever it feels like it. Versions 5.1, 5.2, 5.3, and 5.4 update at a frantic pace, but after all of that most people felt 5.2 was best. 5.4 speaks like a machine and has high information redundancy; it is messy enough that an ADHD reader can finish a long paragraph without absorbing a sentence.&lt;/p&gt;
&lt;p&gt;Claude, by contrast, has consistently pursued mathematics, coding, and logic. Its naming and iteration are rigorous and romantic, drawn from Greek mythology. And when a name changes, it is a real major update—for example, Fable.&lt;/p&gt;
&lt;p&gt;At present, GPT has only 5.6 sol and terra that I find usable. Below 5.6, there is confusion, disorder, and a lack of trust.&lt;/p&gt;
&lt;p&gt;I do not understand OpenAI. I do not understand how it can play such a strong hand so badly. I do not understand Codex either. Perhaps its own employees do not, which is why everyone recommends connecting 5.6 to Claude Code for the best experience XD.&lt;/p&gt;
&lt;h3&gt;What to Watch: There Is No Migration Value Yet, Only Migration Risk&lt;/h3&gt;
&lt;p&gt;What we care about more is the value of migrating.&lt;/p&gt;
&lt;p&gt;But it appears newapi&apos;s native Responses support and translation are currently poor, with much technical debt. It only makes sure replies can get through without error; almost none of the real features are preserved. Instead, quite a few things are stripped away.&lt;/p&gt;
&lt;p&gt;Most people currently cannot reach a true Responses API. In other words, continuing to use &lt;code&gt;chat_completion&lt;/code&gt; is best for us. newapi&apos;s support for it has matured for more than three years; there is no need to gamble on switching to &lt;code&gt;responses&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;What Is the Real Difference Between responses and chat_completion?&lt;/h2&gt;
&lt;p&gt;Earlier, Responses seemed to support things like &lt;code&gt;store=true&lt;/code&gt;, which could hit caches across turns and preserve reasoning. Is the main optimization point only better cache hits, or is there more?&lt;/p&gt;
&lt;p&gt;:::note[Opus]
&lt;strong&gt;Far more. And caching is not “a feature”; it is a byproduct of the other changes. Reversing that causal relationship makes it impossible to see what this protocol transition actually changed.&lt;/strong&gt;&lt;/p&gt;
&lt;h3&gt;A Table That Covers It&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Dimension&lt;/th&gt;
&lt;th&gt;Chat Completions&lt;/th&gt;
&lt;th&gt;Responses&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Endpoint&lt;/td&gt;
&lt;td&gt;&lt;code&gt;/v1/chat/completions&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;/v1/responses&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Input&lt;/td&gt;
&lt;td&gt;&lt;code&gt;messages&lt;/code&gt; array&lt;/td&gt;
&lt;td&gt;&lt;code&gt;input&lt;/code&gt; (string or Item array) plus top-level &lt;code&gt;instructions&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Output&lt;/td&gt;
&lt;td&gt;&lt;code&gt;choices[0].message.content&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;&lt;code&gt;output&lt;/code&gt;&lt;/strong&gt;: an ordered array of typed Items, each with its own &lt;code&gt;id&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Tool definitions&lt;/td&gt;
&lt;td&gt;Nested &lt;code&gt;{type:&quot;function&quot;, function:{name,...}}&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Flat &lt;code&gt;{type:&quot;function&quot;, name:...}&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Tool results&lt;/td&gt;
&lt;td&gt;Put back into &lt;code&gt;messages&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Separate Items, linked by &lt;code&gt;call_id&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;strict&lt;/td&gt;
&lt;td&gt;Off by default&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;On by default&lt;/strong&gt;; use &lt;code&gt;strict:false&lt;/code&gt; only for incompatibility&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Structured output&lt;/td&gt;
&lt;td&gt;&lt;code&gt;response_format&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;text.format&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Built-in tools&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;td&gt;&lt;code&gt;web_search&lt;/code&gt; / &lt;code&gt;file_search&lt;/code&gt; / &lt;code&gt;tool_search&lt;/code&gt; / &lt;code&gt;code_interpreter&lt;/code&gt; / &lt;strong&gt;remote MCP&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Multi-turn&lt;/td&gt;
&lt;td&gt;Manually resend all &lt;code&gt;messages&lt;/code&gt; each turn&lt;/td&gt;
&lt;td&gt;&lt;code&gt;previous_response_id&lt;/code&gt; or a &lt;code&gt;conversation&lt;/code&gt; object&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;State&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;td&gt;&lt;code&gt;store&lt;/code&gt; (stored for 30 days by default; can be disabled)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;reasoning&lt;/td&gt;
&lt;td&gt;Discarded&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Native &lt;code&gt;reasoning&lt;/code&gt; Items&lt;/strong&gt;, including &lt;code&gt;encrypted_content&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Streaming&lt;/td&gt;
&lt;td&gt;Opaque &lt;code&gt;delta&lt;/code&gt; chunks&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Semantic events&lt;/strong&gt;: &lt;code&gt;response.output_item.added&lt;/code&gt; / &lt;code&gt;response.output_text.delta&lt;/code&gt; / &lt;code&gt;response.completed&lt;/code&gt;…&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Async&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;td&gt;&lt;code&gt;background: true&lt;/code&gt; plus polling&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Resume after disconnect&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;td&gt;&lt;code&gt;starting_after&lt;/code&gt; cursor (SDK support “coming soon”)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3&gt;Only Four Points Really Matter&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;1. &lt;code&gt;output&lt;/code&gt; is a typed Item array—the root of every other difference.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;In chat, the result of a turn must be flattened into the three slots &lt;code&gt;role&lt;/code&gt;, &lt;code&gt;content&lt;/code&gt;, and &lt;code&gt;tool_calls&lt;/code&gt;. In Responses, it is a sequence of peer entries, each with an ID and lifecycle. The earlier &lt;code&gt;agent_message&lt;/code&gt;, &lt;code&gt;namespace&lt;/code&gt; tools, and encrypted task delegation do not fit in chat for this exact reason.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;2. Hosted tools run on the server, and a single request can call tools continuously.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The documentation says the model “automatically decides whether to use a configured tool,” and “Some advanced workflows can also load more tool definitions during the interaction” (&lt;code&gt;tool_search&lt;/code&gt;, GPT-5.4+ only). &lt;strong&gt;This directly answers the later question of why a long ToolCall chain can appear not to involve repeated handshakes&lt;/strong&gt;: for built-in tools, it does not, because control never returns to the client. Your own function tools must still return to the client, and that distinction is crucial.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;3. Reasoning Items survive across turns; cache gains are a side effect.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;For stateless calls, the documentation requires you to “preserve &lt;strong&gt;every&lt;/strong&gt; item in the response&apos;s &lt;code&gt;output&lt;/code&gt; array.” Why can cache utilization improve by 40%–80%? Not because a cache was added, but because &lt;strong&gt;the prefix becomes stable&lt;/strong&gt;: chat manually rebuilds &lt;code&gt;messages&lt;/code&gt; every turn and loses reasoning, so the prefix changes constantly; Responses continues with &lt;code&gt;previous_response_id&lt;/code&gt; and preserves reasoning as-is, making the prefix a chain that only grows. The +3% SWE-bench score follows for the same reason: reasoning is no longer cut off, not because of caching.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;4. Streaming changes from a black box to a white box.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Chat SSE is just a sequence of &lt;code&gt;delta&lt;/code&gt;s, so you must infer whether a segment is text or tool arguments. Responses events include a &lt;code&gt;type&lt;/code&gt;: &lt;code&gt;output_item.added&lt;/code&gt; explicitly tells you a new reasoning, message, or function_call Item has begun. &lt;strong&gt;The token-level demonstration you want is directly readable in Responses; in chat, it must be inferred.&lt;/strong&gt; This may be more valuable to your later questions than caching is.&lt;/p&gt;
&lt;h3&gt;But the Conclusion Does Not Change&lt;/h3&gt;
&lt;p&gt;I would not revise the earlier recommendation: &lt;strong&gt;do not migrate yet.&lt;/strong&gt; What you can actually use from those four points depends on the middle hop, and newapi&apos;s fallback channel loses reasoning Items and tool metadata (&lt;a href=&quot;https://github.com/QuantumNous/new-api/issues/6396&quot;&gt;#6396&lt;/a&gt; / &lt;a href=&quot;https://github.com/QuantumNous/new-api/pull/6449&quot;&gt;#6449&lt;/a&gt; / &lt;a href=&quot;https://github.com/QuantumNous/new-api/issues/5938&quot;&gt;#5938&lt;/a&gt;). &lt;strong&gt;You would spend effort migrating only to receive a Responses shell translated back into chat semantics, with none of the four benefits intact.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;What is worth recording is the &lt;strong&gt;condition that should trigger migration&lt;/strong&gt;, not migration itself: when you can reach a native Responses upstream without fallback translation, point 4 (semantic streaming) and point 2 (server-side tool chains) become what your desktop companion actually needs. Cache is the least compelling reason to migrate.
:::&lt;/p&gt;
&lt;h3&gt;Complaining Again&lt;/h3&gt;
&lt;p&gt;I think I understand.&lt;/p&gt;
&lt;p&gt;It turns the very strange data structure of &lt;code&gt;choices[0].message.content&lt;/code&gt; into a white box that looks like something Pydantic can validate. It also replaces the many &lt;code&gt;type unknown&lt;/code&gt; errors I used to get while writing streaming code with native support.&lt;/p&gt;
&lt;p&gt;When I first encountered the OpenAI library, I wondered how a PyPI package used by so many people could be full of pyright errors and require so many &lt;code&gt;type:ignore&lt;/code&gt;s. Its type enforcement was a complete mess. Looking at only a short code fragment, you often could not know what it returned because every possible kind of content was wrapped in the shell of &lt;code&gt;content&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;How can such a large company design data structures so carelessly?&lt;/p&gt;
&lt;p&gt;When I supported FastMCP, the biggest obstacle came from OpenAI&apos;s chat_completion. Its ToolCall handling was exhausting to read. Later, I removed FastMCP entirely, and it felt wonderful.&lt;/p&gt;
&lt;p&gt;But is &lt;code&gt;responses&lt;/code&gt; really designed well? Is its data structure actually cleanly validated? I do not believe it. I have too much distrust of OpenAI. Its past roughness, unreasonableness, and chaotic disorder make it feel like an amateur troupe.&lt;/p&gt;
&lt;h2&gt;The Difference Between Anthropic Messages and the Chat Completion Tool Stream Used by My Desktop Companion&lt;/h2&gt;
&lt;h3&gt;The Confusion Around Talking While Working&lt;/h3&gt;
&lt;p&gt;I need an answer to the question above.&lt;/p&gt;
&lt;p&gt;Why did Claude once tell me that only Anthropic Messages could truly meet my desktop companion&apos;s need to talk while working, while OpenAI could only execute all tools and reply afterward? In practice, after injecting the pre_tool_preview plugin, I saw it give a preview before executing a tool.&lt;/p&gt;
&lt;p&gt;I have forgotten the implementation details and may need to confirm them: &lt;a href=&quot;https://github.com/XnneHangLab/XnneHangLab&quot;&gt;XnneHangLab&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;:::note[Opus]
&lt;strong&gt;That earlier statement was half right and half wrong. Anthropic does natively talk while working, but OpenAI is not “unable to do it”—it is “unable to express multiple segments.” Your plugin did not break through the protocol; it used a field combination the protocol already permits but models do not normally choose.&lt;/strong&gt;&lt;/p&gt;
&lt;h3&gt;Anthropic: Talking While Working Is the Default in the Official Example&lt;/h3&gt;
&lt;p&gt;The &lt;a href=&quot;https://platform.claude.com/docs/en/build-with-claude/streaming&quot;&gt;official streaming documentation&lt;/a&gt; gives this tool-use example verbatim:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;content_block_start  index:0  {&quot;type&quot;:&quot;text&quot;}
content_block_delta  index:0  &quot;Okay&quot; &quot;,&quot; &quot; let&quot; &quot;&apos;s&quot; &quot; check&quot; &quot; the&quot; &quot; weather&quot; ...
content_block_stop   index:0
content_block_start  index:1  {&quot;type&quot;:&quot;tool_use&quot;,&quot;name&quot;:&quot;get_weather&quot;}
content_block_delta  index:1  {&quot;type&quot;:&quot;input_json_delta&quot;,&quot;partial_json&quot;:&quot;{\&quot;location\&quot;:&quot;}
content_block_stop   index:1
message_delta                 {&quot;stop_reason&quot;:&quot;tool_use&quot;}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;The model itself says “Okay, let me check the weather in San Francisco” first, then emits &lt;code&gt;tool_use&lt;/code&gt;—without prompt injection.&lt;/strong&gt; What you gained through a plugin is the first documented example on Anthropic&apos;s side.&lt;/p&gt;
&lt;p&gt;Its &lt;code&gt;content&lt;/code&gt; is also an &lt;strong&gt;ordered array of blocks&lt;/strong&gt;, where &lt;code&gt;index&lt;/code&gt; is the final array position. The web-search example is even more extreme: &lt;code&gt;text(0) → server_tool_use(1) → tool_result(2) → text(3) → …&lt;/code&gt;, continuing to &lt;code&gt;index:17&lt;/code&gt;. &lt;strong&gt;Text and tools genuinely alternate in multiple segments within one message.&lt;/strong&gt;&lt;/p&gt;
&lt;h3&gt;OpenAI: It Can Speak Once, but Cannot Express Multiple Segments&lt;/h3&gt;
&lt;p&gt;An assistant message in chat completions has &lt;code&gt;content&lt;/code&gt;—a &lt;strong&gt;single string&lt;/strong&gt;—and a &lt;code&gt;tool_calls&lt;/code&gt; array as two &lt;strong&gt;parallel fields&lt;/strong&gt;. Therefore:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;One preview plus a batch of tool calls is completely valid.&lt;/strong&gt; Your plugin working is not a hack.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Speak → work → speak → work cannot be expressed.&lt;/strong&gt; There is only one &lt;code&gt;content&lt;/code&gt; string, with nowhere to place a second segment.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;There is a subtler point: &lt;strong&gt;ordering information is lost when the message is saved back.&lt;/strong&gt; During streaming, you really receive &lt;code&gt;delta.content&lt;/code&gt; before &lt;code&gt;delta.tool_calls&lt;/code&gt;—autoregressive generation means generation order is arrival order. But once assembled, it becomes two parallel fields. In the next turn, the model sees &lt;code&gt;{content: &quot;Let me take a screenshot&quot;, tool_calls: [...]}&lt;/code&gt;. &lt;strong&gt;The structure itself no longer says “I spoke first, then acted”;&lt;/strong&gt; it can only infer that semantically. Anthropic&apos;s &lt;code&gt;index&lt;/code&gt; preserves it structurally.&lt;/p&gt;
&lt;h3&gt;Your Implementation: Confirmed from the Repository&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Question&lt;/th&gt;
&lt;th&gt;Answer&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Where is the injection?&lt;/td&gt;
&lt;td&gt;&lt;code&gt;type = &quot;policy&quot;&lt;/code&gt;, &lt;code&gt;injection_position = &quot;before_tools&quot;&lt;/code&gt;, &lt;code&gt;priority = 10&lt;/code&gt;. It goes through &lt;code&gt;PolicyPlugin.get_prompt_segments()&lt;/code&gt; → &lt;code&gt;SystemPromptBuilder.build()&lt;/code&gt;, &lt;strong&gt;into the system prompt before tool definitions&lt;/strong&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;When is it injected?&lt;/td&gt;
&lt;td&gt;Once when creating the agent through &lt;code&gt;AgentFactory.create_core_with_profile()&lt;/code&gt;, &lt;strong&gt;not as a hook every turn&lt;/strong&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Does the preview have the full tool schema?&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Yes.&lt;/strong&gt; The prompt is in the system prompt, while tools are passed in full through &lt;code&gt;stream_with_tools(tools=tools_schema)&lt;/code&gt; in the same API request.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Which LLM call makes the preview?&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;The same call that decides to call the tool, not an extra call.&lt;/strong&gt; Preview tokens and tool_call tokens come from the same completion.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Are preview tokens before or after tool tokens?&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Before.&lt;/strong&gt; In the &lt;code&gt;core.py&lt;/code&gt; loop, &lt;code&gt;delta.content&lt;/code&gt; arrives first, accumulates into &lt;code&gt;text_buf&lt;/code&gt;, and is yielded directly to the user; &lt;code&gt;delta.tool_calls&lt;/code&gt; arrives later and accumulates in &lt;code&gt;tool_calls_buf&lt;/code&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;How many previews can it make?&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;One per round&lt;/strong&gt; because there is only one &lt;code&gt;content&lt;/code&gt;. With &lt;code&gt;max_rounds = 6&lt;/code&gt;, it can make &lt;strong&gt;up to six segments&lt;/strong&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Are staged previews in a long chain supported?&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Yes, at one segment per round&lt;/strong&gt;, not multiple segments within a single round.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The key assembly code is exactly the “one message carrying both a preview and tool_calls” combination:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;assistant_payload = {
    &quot;role&quot;: &quot;assistant&quot;,
    &quot;content&quot;: text_buf or None,   # ← preview text goes here
    &quot;tool_calls&quot;: [...],
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So &lt;strong&gt;you were already using a valid combination allowed by the protocol. Models simply do not do it by default; your prompt calls that behavior forth.&lt;/strong&gt;&lt;/p&gt;
&lt;h3&gt;Where “OpenAI Cannot” Is Wrong and Right&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Anthropic Messages&lt;/th&gt;
&lt;th&gt;OpenAI Chat Completions&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Speak once, then act, within one round&lt;/td&gt;
&lt;td&gt;✅ Native default&lt;/td&gt;
&lt;td&gt;✅ Possible, but needs prompt guidance&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Multiple segments within one round&lt;/td&gt;
&lt;td&gt;✅ (server-tool example reaches index 17)&lt;/td&gt;
&lt;td&gt;❌ Only one &lt;code&gt;content&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Ordering preserved structurally&lt;/td&gt;
&lt;td&gt;✅ &lt;code&gt;index&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;❌ Two parallel fields&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Staged previews across rounds&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅ (your six rounds)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;The right part&lt;/strong&gt;: Anthropic is native behavior and supports multiple segments within a round; OpenAI has neither.
&lt;strong&gt;The wrong part&lt;/strong&gt;: “OpenAI can only execute all tools and reply afterward.” No: one spoken preview per round is protocol-legal, and your plugin proves it.&lt;/p&gt;
&lt;p&gt;The real gap is &lt;strong&gt;small in client-tool scenarios&lt;/strong&gt;. When Anthropic encounters a client tool, it also ends with &lt;code&gt;stop_reason: &quot;tool_use&quot;&lt;/code&gt;, returns to the client, and produces one segment per round. The source of true multiple alternations is &lt;strong&gt;server tools&lt;/strong&gt;: tools run on the server, control never returns to the client, and one message can proceed text → tool → result → text. Chat completions has no server tools, so it can never do this. &lt;strong&gt;That is exactly the gap Responses fills.&lt;/strong&gt;
:::&lt;/p&gt;
&lt;h2&gt;The Limits of pre_tool_preview Under the OpenAI Protocol&lt;/h2&gt;
&lt;p&gt;Okay, I remember. That is indeed how it worked. Multiple segments cannot be expressed: after one preview at the beginning, it gets to work in silence, and if a second tool is needed it cannot preview again.&lt;/p&gt;
&lt;p&gt;For example, this is legal:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Let me read the recent diary.
Tool Call: Read Diary
Tool Result: {...}
I found ...
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;But this cannot be done:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Let me read the recent diary.
Tool Call: Read Diary
Tool Result: {Diary Folder is empty}
The Diary seems empty; let me check recent memories.
Tool Call: Read Memory
Tool Result: {...}
I found...
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Instead, it becomes:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Let me read the recent diary.
Tool Call: Read Diary
Tool Result: {Diary Folder is empty}
Tool Call: Read Memory
Tool Result: {...}
I found there seems to be no diary, ...
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That means users lose awareness after the first preview. If the tool chain becomes extremely long, we cannot perceive what it is doing midway through.&lt;/p&gt;
&lt;h3&gt;Additional Questions&lt;/h3&gt;
&lt;p&gt;I want to understand two things.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Do Anthropic Messages and OpenAI both strictly alternate in sequence? In other words, will no ToolCall token be sent before all preview message tokens are complete?&lt;/li&gt;
&lt;li&gt;Why does the OpenAI protocol not support alternation? Is this a limitation of model output? Do most models have it, or is the protocol simply badly designed?&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;:::note[Opus]
&lt;strong&gt;a: Yes. Both are strictly serial; “alternation” was the wrong word from the start. b: This is purely a protocol problem, not a model limitation—and the evidence is in OpenAI&apos;s own SDK types. Also, the behavior in your example may be caused by your prompt rather than the protocol; see the final section.&lt;/strong&gt;&lt;/p&gt;
&lt;h3&gt;a. Both Are Strictly Serial; There Is No Token-Level Interleaving&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Anthropic&lt;/strong&gt;: the &lt;a href=&quot;https://platform.claude.com/docs/en/build-with-claude/streaming&quot;&gt;official streaming documentation&lt;/a&gt; defines the flow strictly:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;A series of content blocks, each of which has a &lt;code&gt;content_block_start&lt;/code&gt;, one or more &lt;code&gt;content_block_delta&lt;/code&gt; events, and a &lt;code&gt;content_block_stop&lt;/code&gt; event.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;That means &lt;strong&gt;block 0 must finish with &lt;code&gt;content_block_stop&lt;/code&gt; before block 1 can start with &lt;code&gt;content_block_start&lt;/code&gt;&lt;/strong&gt;. In the official example, the final &lt;code&gt;text_delta&lt;/code&gt; from “Okay, let&apos;s check the weather...” arrives, then &lt;code&gt;content_block_stop index:0&lt;/code&gt;, and only then does &lt;code&gt;content_block_start index:1&lt;/code&gt; begin the &lt;code&gt;tool_use&lt;/code&gt;. &lt;strong&gt;There is no mixing of &lt;code&gt;text_delta(0)&lt;/code&gt; and &lt;code&gt;input_json_delta(1)&lt;/code&gt; in the stream.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;OpenAI&lt;/strong&gt; is similarly autoregressive: &lt;code&gt;delta.content&lt;/code&gt; arrives first, followed by &lt;code&gt;delta.tool_calls&lt;/code&gt;, also in sequence.&lt;/p&gt;
&lt;p&gt;So the accurate statement is: &lt;strong&gt;both providers concatenate &lt;code&gt;[text-token segment][tool-token segment]&lt;/code&gt; in sequence; the difference is only how many segments can be joined.&lt;/strong&gt;&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Shapes it can join&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Anthropic&lt;/td&gt;
&lt;td&gt;&lt;code&gt;[text][tool][text][tool]…&lt;/code&gt; (the server-tool example reaches &lt;code&gt;index:17&lt;/code&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;OpenAI chat&lt;/td&gt;
&lt;td&gt;&lt;code&gt;[text][tool]&lt;/code&gt;—only this one pair&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;“Alternation” should be renamed “segmentation.”&lt;/strong&gt; What your original question meant by “alternating tool tokens and chat tokens” was segmentation ability, not mixed token streaming. Neither provider does the latter, and neither should; a client cannot render a half-sentence with an inserted tool call.&lt;/p&gt;
&lt;h3&gt;b. It Is the Protocol, Not the Model—the Proof Is in OpenAI&apos;s Own Type Definitions&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Evidence one: the same model can create multiple segments when the protocol changes.&lt;/strong&gt; &lt;code&gt;gpt-5.x&lt;/code&gt; under Responses can legally produce an output array like &lt;code&gt;message → function_call → message → function_call&lt;/code&gt;; the same model under chat completions cannot. &lt;strong&gt;The model is unchanged, and capability changes with the protocol.&lt;/strong&gt; That alone excludes model-output limitations.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Evidence two: the asymmetry in openai-python is obvious.&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# Output (what the model sends you) — chat_completion_message.py
class ChatCompletionMessage(BaseModel):
    content: Optional[str] = None          # ← one string

# Input (what you send back) — chat_completion_assistant_message_param.py
ContentArrayOfContentPart: TypeAlias = Union[
    ChatCompletionContentPartTextParam,
    ChatCompletionContentPartRefusalParam,  # ← only text and refusal
]
content: Union[str, Iterable[ContentArrayOfContentPart], None]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Two things are true at once:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Assistant content can already be an array on the input side, while output remains a string.&lt;/strong&gt; The array shape exists in the protocol but was never extended to model output.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Even that array contains only &lt;code&gt;text&lt;/code&gt; and &lt;code&gt;refusal&lt;/code&gt;, not a tool_call part.&lt;/strong&gt; So even manually constructing it cannot represent an ordered “text → tool → text” sequence; &lt;code&gt;tool_calls&lt;/code&gt; always remains another parallel field.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;That is the root problem: it is not that no array exists, but that the array has no tools.&lt;/strong&gt; The protocol contains nowhere that can preserve ordering information.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Evidence three: chat completions is the odd one out among major providers.&lt;/strong&gt; Gemini&apos;s &lt;code&gt;Content.parts&lt;/code&gt; is also a mixed array, and its documentation explicitly warns:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;the model may return a mix of &lt;code&gt;functionCall&lt;/code&gt;, &lt;code&gt;toolCall&lt;/code&gt;, and &lt;code&gt;toolResponse&lt;/code&gt; parts in a single turn. &lt;strong&gt;Don&apos;t assume the &lt;code&gt;functionCall&lt;/code&gt; will always be the last item in the parts array.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;That is effectively saying that text can occur after a &lt;code&gt;functionCall&lt;/code&gt;. Anthropic has ordered blocks; Gemini has ordered parts; Responses has ordered items. &lt;strong&gt;Only chat completions uses two parallel fields.&lt;/strong&gt;&lt;/p&gt;
&lt;h3&gt;Is It Really “Garbage Design”?&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Not garbage, but unreconstructed historical baggage.&lt;/strong&gt; &lt;code&gt;content: str&lt;/code&gt; made perfect sense in the GPT-3.5 era, when a turn could only produce text. When function calling was added in 2023, &lt;strong&gt;adding a parallel &lt;code&gt;tool_calls&lt;/code&gt; field was backward compatible; changing &lt;code&gt;content&lt;/code&gt; from a string to an ordered array was not&lt;/strong&gt;. It would have broken every client that read &lt;code&gt;choices[0].message.content&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;That locked it in. Multimodal input later received an array because it was a new field and new shape, while output remained a string forever. &lt;strong&gt;This is why Responses required a new endpoint rather than adding parameters to chat completions: the change could not be compatible, so the protocol had to change.&lt;/strong&gt; It also explains why Codex had to remove support rather than softly preserving it.&lt;/p&gt;
&lt;h3&gt;Finally: Your Example May Be Your Own Prompt&apos;s Fault&lt;/h3&gt;
&lt;p&gt;You said users lose awareness after the first preview. But &lt;strong&gt;across rounds, the multiple-segment restriction does not apply&lt;/strong&gt;. The second assistant message has its own &lt;code&gt;content&lt;/code&gt; field and can legally preview again:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;round 1: {content: &quot;Let me read the diary.&quot;, tool_calls: [read_diary]}
round 2: {content: &quot;The diary is empty; I will check memory.&quot;, tool_calls: [read_memory]}   ← fully legal
round 3: {content: &quot;I found…&quot;}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Why did this not happen? Look at rule five of your own &lt;code&gt;pre_tool_preview&lt;/code&gt; injection:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;“If this is the first tool call in the current round&lt;/strong&gt;, and the user can perceive the wait, prioritize this upfront explanation.”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The phrase &lt;strong&gt;“first tool call in the current round”&lt;/strong&gt; may have been interpreted by the model as “only preview once in a user turn.” The behavior you observed strongly matches that prompt.&lt;/p&gt;
&lt;p&gt;Try a control experiment first: change it to “&lt;strong&gt;Before every&lt;/strong&gt; tool call, give an upfront explanation; if it repeats the previous one, use different wording.” Then see whether a second preview appears. &lt;strong&gt;If it does, your long-chain silence came from the prompt, not the protocol—a vastly easier problem to fix.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;(And a correction to the previous section: saying “once per round, up to six segments” was correct; &lt;code&gt;max_rounds = 6&lt;/code&gt; gives you six-segment budget. What actually consumed one segment and then stopped was likely this prompt rule.)
:::&lt;/p&gt;
&lt;h3&gt;Damn!&lt;/h3&gt;
&lt;p&gt;Oh, I finally understand. I could see only one preview all this time because of my own prompt!&lt;/p&gt;
&lt;p&gt;And in a tool loop, each OpenAI protocol tool-call segment is independent and can carry a preview message?&lt;/p&gt;
&lt;p&gt;This matters greatly to me. My later engineering goal is to eliminate silence in long tool chains for the desktop companion. I had planned to break one tool chain into multiple steps, but now it seems I may not need to!&lt;/p&gt;
&lt;p&gt;Is that right?&lt;/p&gt;
&lt;p&gt;So I only need to improve the prompt and add some guardrails? I do not need a complicated implementation?&lt;/p&gt;
&lt;p&gt;:::note[Opus]
&lt;strong&gt;The overall direction is right, but do not celebrate yet—three points need calibration, and the second one is my responsibility.&lt;/strong&gt;&lt;/p&gt;
&lt;h3&gt;Correction One: It Is “One per Round,” Not “One per Tool”&lt;/h3&gt;
&lt;p&gt;These two lines in your &lt;code&gt;core.py&lt;/code&gt; explain it:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;max_rounds = 6                                    # 503
*(_exec_tool(tc, ...) for tc in ordered_tool_calls)   # 606, parallel execution
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;In one round—one LLM call—the model can emit N tool_calls, which you execute in parallel.&lt;/strong&gt; That round has only one &lt;code&gt;content&lt;/code&gt; field, so &lt;strong&gt;N tools share one preview&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;The precise statement is: &lt;strong&gt;a preview has the granularity of “one per LLM call,” not “one per tool.”&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;For one-to-one previews, pass &lt;code&gt;parallel_tool_calls: false&lt;/code&gt; to the API; it is a standard chat-completions parameter and openai-python types it. But that trades latency for awareness. If three tools each take five seconds, parallel execution takes five seconds while serial execution takes fifteen. &lt;strong&gt;Usually that is not worth it: one preview saying “I will check the diary and memory at the same time” is enough.&lt;/strong&gt;&lt;/p&gt;
&lt;h3&gt;Correction Two: My Diagnosis Was a Hypothesis, Not a Conclusion&lt;/h3&gt;
&lt;p&gt;In the previous section, I said the prompt might be at fault. That was a &lt;strong&gt;high-confidence inference from reading the code, but I did not run your agent&lt;/strong&gt;. Do not treat it as a verified fact—&lt;strong&gt;run the control experiment first&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;And even after changing the prompt, there is a second obstacle: &lt;strong&gt;after getting a tool_result, models themselves tend to jump straight into the next tool call&lt;/strong&gt;. How malleable that behavior is depends on the model. The ones you use on the desktop companion—DeepSeek and Grok-like models—may be more stubborn than frontier models.&lt;/p&gt;
&lt;p&gt;So set realistic expectations: &lt;strong&gt;improving the prompt will probably help substantially, but may not consistently produce a preview every round.&lt;/strong&gt; Prepare for partial success rather than treating one edit as a complete solution.&lt;/p&gt;
&lt;h3&gt;Correction Three: Previews Do Not Remove Silence During Tool Execution&lt;/h3&gt;
&lt;p&gt;This is easiest to overlook. A preview covers &lt;strong&gt;the instant from the LLM deciding to call a tool until the tool starts&lt;/strong&gt;, not &lt;strong&gt;the three to five seconds while the tool runs&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;The real result is therefore:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Before: [say one thing] ────30 seconds of silence──── [answer]
After:  [say one thing]─5s silence─[say one thing]─5s silence─[say one thing]─5s silence─[answer]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;It splits one long silence into several shorter silences; it does not remove silence.&lt;/strong&gt; The perceived improvement is huge, but a tool that itself takes ten seconds remains silent for ten seconds. Only UI-level progress feedback—such as a spinner or “Reading…”—can cover that; the protocol cannot.&lt;/p&gt;
&lt;h3&gt;Do You Still Need to Split It into Steps?&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;If the goal is only to remove silence, no.&lt;/strong&gt; Your original plan to break it down would use engineering to imitate a capability the protocol already has.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;But notice one hard limit: &lt;code&gt;max_rounds = 6&lt;/code&gt;.&lt;/strong&gt; Once a chain exceeds six rounds, your own system truncates it. If you want long tool chains to remain perceptible, raise this number first; no matter how good previews are, the current budget is only six segments.&lt;/p&gt;
&lt;h3&gt;A Concrete Prompt Shape&lt;/h3&gt;
&lt;p&gt;Do not only write “preview before calling.” Make each round&apos;s sentence &lt;strong&gt;both close the previous step and preview the next&lt;/strong&gt;. That is the form you actually want:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Before every tool call, say one sentence. If this is not the first tool call in the current round, that sentence must do two things: use half a sentence to state the previous result, then explain the next action. Do not repeat the previous wording.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The output becomes the ideal form you described:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Let me read the recent diary.                  ← preview only
[Read Diary] → empty
The diary is empty; I will check memory.       ← closure + preview
[Read Memory] → ...
I found...                                     ← closure
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;This is more natural than previewing every step and uses fewer tokens: users receive a coherent narrative rather than six repeated “Let me check…” lines.&lt;/strong&gt;
:::&lt;/p&gt;
&lt;h2&gt;Real and Fake “Talking While Working”&lt;/h2&gt;
&lt;p&gt;I understand now, but I do not understand what advantage Claude has beyond this.&lt;/p&gt;
&lt;p&gt;If both are strictly serial, then they seem no different. Can you explain what truly counts as talking while working (Anthropic), and what is fake talking while working (OpenAI)?&lt;/p&gt;
&lt;p&gt;From my perspective, reaching the form above already feels complete.&lt;/p&gt;
&lt;p&gt;:::note[Opus]
&lt;strong&gt;First, correct a framing error: the boundary between real and fake is not Anthropic versus OpenAI, but server tools versus client tools. By that line, your desktop-companion scenario cannot reach the “real” tier under either provider, so the answer is bad news for you—but it saves you a migration.&lt;/strong&gt;&lt;/p&gt;
&lt;h3&gt;Fake: Segmented Speech, With a Full Round Trip per Segment&lt;/h3&gt;
&lt;p&gt;The multiple segments in chat completions are stitched together by a &lt;strong&gt;client-side loop&lt;/strong&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;HTTP request 1 ──&amp;gt; [preview] [tool_calls]        ← connection ends; control returns to you
   You execute the tool locally
HTTP request 2 ──&amp;gt; [closure + preview] [tool_calls]   ← resend full history; new TTFT
   You execute the tool locally
HTTP request 3 ──&amp;gt; [final answer]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The user sees a coherent narrative, but underneath are &lt;strong&gt;three requests, three full-context submissions, and three time-to-first-token delays&lt;/strong&gt;. It is “&lt;strong&gt;segmented speech&lt;/strong&gt;,” not “talking while working”: between each segment, the model has actually stopped working.&lt;/p&gt;
&lt;h3&gt;Real: Speak, Work, Speak in One Stream, Without Returning Control to the Client&lt;/h3&gt;
&lt;p&gt;Anthropic &lt;strong&gt;server tools&lt;/strong&gt; (&lt;code&gt;web_search&lt;/code&gt; / &lt;code&gt;code_execution&lt;/code&gt; / MCP connector) execute on Anthropic&apos;s servers. The official streaming web-search example looks like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;content_block_start index:0   text          &quot;I&apos;ll check the current weather in NYC for you.&quot;
content_block_start index:1   server_tool_use   web_search
content_block_start index:2   web_search_tool_result   ← server executes and inserts result directly
content_block_start index:3   text          &quot;Here&apos;s the current weather...&quot;
...
content_block_stop  index:17
message_stop                                  ← one HTTP request from start to finish
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;One request, one SSE stream, seventeen blocks.&lt;/strong&gt; Control never returns to the client. This is the literal meaning of “talking while working”: &lt;strong&gt;the work happens while it speaks, without a break in the middle.&lt;/strong&gt;&lt;/p&gt;
&lt;h3&gt;The Honest Part: Anthropic Client Tools Are Fake Too&lt;/h3&gt;
&lt;p&gt;If you define your own &lt;code&gt;get_weather&lt;/code&gt; tool for Anthropic, it still ends with &lt;code&gt;stop_reason: &quot;tool_use&quot;&lt;/code&gt;, still returns to the client, and still requires another request. &lt;strong&gt;It is exactly the same as OpenAI.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The correct dividing line is therefore:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Multiple segments in one request&lt;/th&gt;
&lt;th&gt;Requires a client loop&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Anthropic server tools&lt;/td&gt;
&lt;td&gt;✅ Real&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;OpenAI Responses server tools&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;✅ Real&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Anthropic client tools&lt;/td&gt;
&lt;td&gt;❌ Fake&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;OpenAI chat completions (client tools only)&lt;/td&gt;
&lt;td&gt;❌ Fake&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;Notice the second row.&lt;/strong&gt; Responses also has server tools (&lt;code&gt;web_search&lt;/code&gt; / &lt;code&gt;code_interpreter&lt;/code&gt; / remote MCP), so it can do the real version too. This has never been “Claude is stronger”; &lt;strong&gt;chat completions is simply the only one of the four without a door into that capability.&lt;/strong&gt;&lt;/p&gt;
&lt;h3&gt;What This Means for Your Desktop Companion&lt;/h3&gt;
&lt;p&gt;Your tools are &lt;strong&gt;screenshots, diary reading, and memory reading&lt;/strong&gt;—all of them must execute on the local machine. &lt;strong&gt;They are permanently client tools.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Therefore, you cannot reach the real tier by switching to Anthropic or Responses.&lt;/strong&gt; It is not that protocols withhold it; the tools physically run on a user&apos;s computer, so control must return there.&lt;/p&gt;
&lt;p&gt;What advantages remain for Anthropic over chat completions? Only two:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Better default behavior&lt;/strong&gt;—models speak before acting without requiring &lt;code&gt;pre_tool_preview&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Text-tool ordering is structural within a round&lt;/strong&gt; through &lt;code&gt;index&lt;/code&gt;, rather than relying on the convention that &lt;code&gt;content&lt;/code&gt; precedes &lt;code&gt;tool_calls&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;Neither is worth migrating for.&lt;/strong&gt; You already solve the first with prompting; in your own client, the second has no material advantage over a convention and guarantee.&lt;/p&gt;
&lt;h3&gt;A More Precise Meaning of “Handshake”&lt;/h3&gt;
&lt;p&gt;You have worried about “repeated handshakes causing first-token latency.” But &lt;strong&gt;multi-round exchanges do not normally redo TCP/TLS handshakes&lt;/strong&gt;: &lt;code&gt;openai-python&lt;/code&gt; uses a shared httpx client and reuses keep-alive connections.&lt;/p&gt;
&lt;p&gt;The actual cost of each round is:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Resubmitting full context&lt;/strong&gt; (token cost, mostly offset by prompt caching)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Server-side prefill again&lt;/strong&gt; (also mostly offset by caching)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;TTFT&lt;/strong&gt;, time to first token—&lt;strong&gt;this really exists every round and cannot be removed by caching&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;So a six-round tool chain&apos;s latency mostly comes from &lt;strong&gt;6 × TTFT + 6 × tool execution time&lt;/strong&gt;, not six handshakes. Whether your roommate&apos;s claim that “Responses long connections can remove first-token delay” holds is a separate question. For now, remember: &lt;strong&gt;you want to reduce TTFT, not handshakes.&lt;/strong&gt;
:::&lt;/p&gt;
&lt;p&gt;Okay, just as I expected, the two are not really different. Reaching that form is already the limit if the connection is not kept open.&lt;/p&gt;
&lt;p&gt;Okay, one big confusion gone, one point of clarity gained.&lt;/p&gt;
</content:encoded></item><item><title>Learning from Bad Architecture: What Claude Desktop&apos;s Five Scheduling Systems Reveal About Separating Cowork and Code</title><link>https://xnnehang.top/en/posts/claude-desktop-bridging-problem/</link><guid isPermaLink="true">https://xnnehang.top/en/posts/claude-desktop-bridging-problem/</guid><description>A breakdown of Claude Desktop&apos;s five scheduling systems, the architectural causes behind their complexity, why this design multiplies the effort required to maintain one project, and what a bad architecture can teach us.</description><pubDate>Thu, 23 Jul 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;img src=&quot;../../assets/img/covers/PixPin_2026-07-23_17-28-05.jpg&quot; alt=&quot;Claude Desktop scheduling systems&quot; /&gt;&lt;/p&gt;
&lt;p&gt;:::note
I have a peculiar habit: whenever I encounter something that confuses me, I want to figure it out—at least far enough to resolve the confusion.&lt;/p&gt;
&lt;p&gt;That was how Claude Desktop&apos;s complicated scheduling systems drew me in. After taking them apart, however, I found an architectural mess riddled with legacy problems and code continually wedged in through successive iterations. The rest of this article explains why.&lt;/p&gt;
&lt;p&gt;Why did I persist after realizing halfway through just how twisted the implementation was? Because good architecture is not the only kind worth studying. In fact, it can be harder to understand precisely what makes good architecture good. Bad architecture is different: its problems are apparent at a glance. The ancients learned from history; we can learn from a mess.&lt;/p&gt;
&lt;p&gt;This is an architecture worth knowing how to avoid. Someone else has already stepped into the traps for us. I certainly will not split the underlying &lt;code&gt;agent&lt;/code&gt; system into divergent implementations merely to accommodate different scenarios, because that leads directly to maintaining several parallel systems—effectively multiplying the effort required to maintain a single project. I would rather spin the other scenario into a new project than force both into the same one.
:::&lt;/p&gt;
&lt;h2&gt;Why I Call It an Architectural Mess&lt;/h2&gt;
&lt;p&gt;First, consider Claude Desktop&apos;s three modes: &lt;code&gt;chat&lt;/code&gt;, &lt;code&gt;cowork&lt;/code&gt;, and &lt;code&gt;code&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;What concerns us here is the architectural redundancy, not the elegance of the code itself. The project is not open source, after all.&lt;/p&gt;
&lt;p&gt;Taken separately, both &lt;code&gt;cowork&lt;/code&gt; and &lt;code&gt;code&lt;/code&gt; are excellent. I have used each of them extensively.&lt;/p&gt;
&lt;p&gt;There is not much to say about &lt;code&gt;chat&lt;/code&gt;. Many tools and shell permissions have been stripped away; it is simply chat.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;code&lt;/code&gt; feels as though it shares a core with Claude Code. It has essentially the same tools and slash commands as Claude Code, its logic is very similar, and even its prompts seem consistent.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;cowork&lt;/code&gt; is where the architectural mess begins. Rather than sharing the same Agent system as &lt;code&gt;code&lt;/code&gt;, it appears to have built another independent one. Much of the underlying tool and memory machinery may be shared, but the two also diverge substantially. Cowork, for example, does not expose the range of &lt;code&gt;allow&lt;/code&gt; permissions available in Code. It has shell access, but never with the same comfort as Code&apos;s ability to grant full access; some capabilities also seem to have been removed. For reasons I cannot explain, its shell execution is simply slower than Code&apos;s as well.&lt;/p&gt;
&lt;p&gt;I used Cowork frequently while working on my graduation project—for surveys, presentations, and editing Word documents. With the right skills configured, it is an excellent workbench. But creating that workbench also required sacrificing or cutting down many Code features and prompts, allowing the two implementations to drift apart.&lt;/p&gt;
&lt;p&gt;The particular mess examined here, however, comes from the scheduling systems—or rather, from the deeply counterintuitive architecture revealed by those systems.&lt;/p&gt;
&lt;p&gt;As discussed above, Cowork and Code were built as two Agent systems, so they also require at least two scheduling systems.&lt;/p&gt;
&lt;p&gt;Because Claude Desktop tries to support both local and cloud execution, that number becomes at least four. Code mode also has &lt;code&gt;/loop&lt;/code&gt;, which creates session-scoped scheduled tasks that disappear when the session ends.&lt;/p&gt;
&lt;p&gt;Strictly speaking, then, a single Claude Desktop contains five scheduling systems. They cannot communicate across Cowork and Code; each maintains its own tasks. The Code side calls them Routines, while the Cowork side calls them Scheduled Tasks. Code creates a local Routine by default, whereas Cowork creates a Cloud Scheduled Task by default. Both are created with a tool named &lt;code&gt;create_scheduled_task&lt;/code&gt;, yet the same tool produces different results.&lt;/p&gt;
&lt;p&gt;Code also has &lt;code&gt;/schedule&lt;/code&gt;, which lets users choose between a local and cloud Routine. Cowork has no equivalent &lt;code&gt;/schedule&lt;/code&gt; command. A conversation cannot create a Local Scheduled Task there; users can only change a cloud task to &lt;code&gt;Run on your computer&lt;/code&gt; through the GUI.&lt;/p&gt;
&lt;p&gt;The result is a &lt;code&gt;code vs cowork&lt;/code&gt; divide full of legacy problems, mismatched features, mismatched documentation, and awkward usage.&lt;/p&gt;
&lt;p&gt;This investigation certainly resolved my confusion—by leading me all the way into the architectural mess.&lt;/p&gt;
&lt;h2&gt;Background&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/NevaMind-AI/memU/issues/538&quot;&gt;#538&lt;/a&gt; established that bridging requires a standalone CLI with headless authentication. That raises a natural follow-up question: &lt;strong&gt;Could we avoid installing the CLI and run bridging through Claude Desktop&apos;s native scheduled tasks instead?&lt;/strong&gt; In theory, running inside an already authenticated app might bypass both symptoms described in #538.&lt;/p&gt;
&lt;p&gt;To answer that question, I tested the behavior locally on Windows 11 with Claude Desktop 2.1.181 and compared it against the official documentation. This issue records the survey and its conclusion so that the route does not have to be evaluated again later.&lt;/p&gt;
&lt;p&gt;The conclusion first: &lt;strong&gt;Do not use Desktop&apos;s native scheduling. Keep the &lt;code&gt;claude_code&lt;/code&gt; adapter targeted exclusively at the Claude Code CLI plus the operating system scheduler.&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;The Complete Picture of Claude&apos;s Five Native Scheduling Systems&lt;/h2&gt;
&lt;p&gt;This comparison draws on four sets of documentation: &lt;a href=&quot;https://code.claude.com/docs/en/scheduled-tasks&quot;&gt;scheduled tasks&lt;/a&gt;, &lt;a href=&quot;https://code.claude.com/docs/en/desktop-scheduled-tasks&quot;&gt;Desktop scheduled tasks&lt;/a&gt;, &lt;a href=&quot;https://code.claude.com/docs/en/routines&quot;&gt;Routines&lt;/a&gt;, and &lt;a href=&quot;https://support.claude.com/en/articles/13854387-schedule-recurring-tasks-in-claude-cowork&quot;&gt;Cowork support&lt;/a&gt;.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;System&lt;/th&gt;
&lt;th&gt;Created from&lt;/th&gt;
&lt;th&gt;Runs on&lt;/th&gt;
&lt;th&gt;Can access local files&lt;/th&gt;
&lt;th&gt;Can read all session logs&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Cloud Routine (UI: New routine → Cloud)&lt;/td&gt;
&lt;td&gt;CLI, Desktop, or claude.ai&lt;/td&gt;
&lt;td&gt;Anthropic cloud, with a fresh clone each time&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Local Routine (UI: New routine → Local; Code mode tool: &lt;code&gt;create_scheduled_task&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;Desktop only: choose Local on the Routines page, or use the tool in a Code session&lt;/td&gt;
&lt;td&gt;Local machine; runs only while the app is open&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Session-scoped tasks&lt;/td&gt;
&lt;td&gt;CLI &lt;code&gt;/loop&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Local machine, tied to the session&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes, but they disappear with the session&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cloud Cowork Scheduled Tasks (UI: Home → Scheduled → New task; Cowork mode tool: &lt;code&gt;create_scheduled_task&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;Cowork session or the Scheduled section on Home&lt;/td&gt;
&lt;td&gt;Anthropic cloud sandbox&lt;/td&gt;
&lt;td&gt;Conditional, bridged only while the app is online&lt;/td&gt;
&lt;td&gt;Unreliable&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Local Cowork Scheduled Tasks (UI: Home → Scheduled → New task → &lt;code&gt;Run on your computer&lt;/code&gt;; cannot be reproduced through &lt;code&gt;create_scheduled_task&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;Cowork session or the Scheduled section on Home&lt;/td&gt;
&lt;td&gt;Local machine; runs only while the app is open&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;One additional detail deserves attention. When a Claude Desktop conversation uses the built-in &lt;code&gt;create_scheduled_task&lt;/code&gt; tool in Code mode, it creates a Local Routine by default. That Routine silently binds its &lt;code&gt;cwd&lt;/code&gt; to the working directory of the session in which it was created. If the directory is later deleted, the task loses the directory it expects to activate when it runs and begins to fail.&lt;/p&gt;
&lt;p&gt;In Cowork mode, &lt;code&gt;create_scheduled_task&lt;/code&gt; creates a Cloud Scheduled Task by default. It can be manually changed to &lt;code&gt;Run on your computer&lt;/code&gt;, turning it into a local scheduled task, but this operation is difficult to reproduce conversationally—or rather, Cowork explicitly refuses to do so. &lt;strong&gt;Even if I ask it to create ten more scheduled tasks, every one still runs in the cloud.&lt;/strong&gt; No tool allows Cowork to create a local Scheduled Task directly. It even suggests using cron on macOS or Linux, or offers to help write an equivalent for Windows. &lt;code&gt;Run on your computer&lt;/code&gt; is accessible only through the GUI and must be configured manually. It is a Beta feature and presumably has not yet been exposed through a tool.&lt;/p&gt;
&lt;p&gt;There is also a gap in the official documentation worth pointing out. The &lt;a href=&quot;https://code.claude.com/docs/en/routines&quot;&gt;Routines documentation&lt;/a&gt; defines Routines as scheduled systems that run only in the Anthropic cloud, while the &lt;a href=&quot;https://code.claude.com/docs/en/desktop-scheduled-tasks&quot;&gt;Desktop scheduled tasks documentation&lt;/a&gt; calls the local variant a Desktop scheduled task. Yet the latter describes a UI flow that says, “click &lt;strong&gt;New routine&lt;/strong&gt; and choose &lt;strong&gt;Local&lt;/strong&gt;.” The terminology in the Desktop UI is therefore misaligned. The documentation itself has not been fully synchronized and its naming has drifted. In Desktop, both kinds of task can be manually switched between local and cloud execution through the UI, but neither system appears to offer a complete, reliable built-in mechanism for triggering that migration through conversation.&lt;/p&gt;
&lt;h2&gt;Testing the Entry-Point Routing: &lt;code&gt;/schedule&lt;/code&gt; and &lt;code&gt;create_scheduled_task&lt;/code&gt;, Same Names but Different Backends&lt;/h2&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/img/covers/claude-desktop-routing.png&quot; alt=&quot;Routing among Claude Desktop scheduling systems&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Three findings from direct testing—all verified through persisted files or transcripts rather than paraphrased from documentation:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;create_scheduled_task&lt;/code&gt; creates a local task in a Code session&lt;/strong&gt;, as verified by the persisted &lt;code&gt;SKILL.md&lt;/code&gt;, but &lt;strong&gt;creates a cloud task in a Cowork session&lt;/strong&gt;, which describes itself as something that “spins up a fresh session in a cloud sandbox, so your computer doesn&apos;t need to be on.” The same tool name routes to two opposing backends.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;There are two &lt;code&gt;/schedule&lt;/code&gt; entry points.&lt;/strong&gt; Typing &lt;code&gt;/schedule&lt;/code&gt; in a Desktop Code session invokes a skill from the &lt;code&gt;anthropic-skills&lt;/code&gt; plugin, persisted under &lt;code&gt;%APPDATA%\Claude\local-agent-mode-sessions\skills-plugin\...&lt;/code&gt;. Its instructions end with “Finally, call the &lt;code&gt;create_scheduled_task&lt;/code&gt; tool,” which produces a &lt;strong&gt;local&lt;/strong&gt; task. In the CLI documentation, however, &lt;code&gt;/schedule&lt;/code&gt; creates a &lt;strong&gt;cloud&lt;/strong&gt; Routine. Direct testing also found &lt;code&gt;/schedule&lt;/code&gt; only in Code sessions; Cowork and ordinary Chat sessions do not expose it.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Ordinary Chat sessions expose neither mechanism.&lt;/strong&gt; Chat is not a scheduling surface.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Code&apos;s Local Tasks vs Cowork&apos;s Scheduled Tasks: The Two Users Are Most Likely to Confuse&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Dimension&lt;/th&gt;
&lt;th&gt;Local Routine created in a Code session&lt;/th&gt;
&lt;th&gt;Cowork Scheduled Task&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Execution environment&lt;/td&gt;
&lt;td&gt;Local machine, inside the Desktop app process&lt;/td&gt;
&lt;td&gt;Anthropic cloud sandbox&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;App or machine shut down&lt;/td&gt;
&lt;td&gt;Does not run; on wake, catches up only the most recent occurrence within a seven-day window&lt;/td&gt;
&lt;td&gt;Continues running&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Local files&lt;/td&gt;
&lt;td&gt;Full access (&lt;code&gt;cwd&lt;/code&gt; is only the starting point, not a sandbox)&lt;/td&gt;
&lt;td&gt;Conditional bridging while the app is online; no formal documentation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Access to all &lt;code&gt;~/.claude/projects&lt;/code&gt; sessions&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Unreliable&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Authentication&lt;/td&gt;
&lt;td&gt;Inherits the app login; no CLI or token required&lt;/td&gt;
&lt;td&gt;Managed in the cloud&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Local representation&lt;/td&gt;
&lt;td&gt;Two persisted layers: &lt;code&gt;SKILL.md&lt;/code&gt; plus a registry&lt;/td&gt;
&lt;td&gt;None; there is nothing that can be “moved to local”&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;At first glance, a Local Routine seems perfect for hosting the memu-cli scheduling system.&lt;/p&gt;
&lt;p&gt;But Routines have a fatal flaw: when a scheduled task is created, its &lt;code&gt;cwd&lt;/code&gt; is automatically bound to the project directory of the creating session. If that project folder is deleted, the Routine loses its working directory and fails. Although it can access the complete collection of sessions, it was designed only for work inside a Project.&lt;/p&gt;
&lt;p&gt;Another uncontrollable factor is that we cannot predict whether users will install memu-cli from Cowork or Code. In Cowork, moreover, we cannot reliably change a Routine to &lt;code&gt;Run on your computer&lt;/code&gt; through conversation.&lt;/p&gt;
&lt;h2&gt;Why We Are Not Splitting the &lt;code&gt;claude_code&lt;/code&gt; Adapter into Separate CLI and Desktop Implementations&lt;/h2&gt;
&lt;p&gt;A local Desktop Scheduled Task is tempting in isolation: the app is already authenticated and can read every session. As a registration target for an &lt;strong&gt;installer&lt;/strong&gt;, however, direct testing exposed too many problems in its mechanism:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;The detection criterion is unstable.&lt;/strong&gt; Identically named tools and commands route to opposite backends on different surfaces, so an Agent cannot determine its environment from the name alone. The only reliable criterion is to create a task and then check whether a &lt;code&gt;SKILL.md&lt;/code&gt; file was persisted, making installation logic complicated and brittle.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The entry point is extremely narrow.&lt;/strong&gt; Local tasks can be created only from a Desktop Code session. The terminal CLI has no entry point. Manually placing a &lt;code&gt;SKILL.md&lt;/code&gt; file creates an orphan: testing showed that a complete &lt;code&gt;memu-bridging/SKILL.md&lt;/code&gt; outside the registry is never scheduled. Editing the registry manually at &lt;code&gt;%APPDATA%\Claude\claude-code-sessions\...\scheduled-tasks.json&lt;/code&gt; creates a dead letter: in testing, the edit survived for seven minutes before the app&apos;s in-memory copy overwrote the entire entry at the next scheduling tick. &lt;strong&gt;The installer has no registration path outside a session.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The &lt;code&gt;cwd&lt;/code&gt; binding is hidden.&lt;/strong&gt; Every task in the registry silently captures a &lt;code&gt;cwd&lt;/code&gt; equal to the working directory of the session that created it. The tool exposes no parameter for it and no way to update it. Behavior after that directory is deleted is undocumented and remains unresolved in testing.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The mechanism is still rolling out, and the documentation itself has gaps.&lt;/strong&gt; Documentation and direct testing diverge—for example, Cowork support documentation says &lt;code&gt;/schedule&lt;/code&gt; exists, while testing found that it does not. The documentation, UI, and tools use three mutually contradictory naming schemes. Surface semantics drift between versions, making this unsuitable as a third-party installation target.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The benefit is not exclusive.&lt;/strong&gt; Transcripts from Desktop Code sessions and the CLI are stored under the same &lt;code&gt;~/.claude/projects&lt;/code&gt; directory. &lt;strong&gt;A bridging pipeline built on the CLI plus the operating system scheduler naturally covers data created by Desktop users, so avoiding Desktop&apos;s native scheduling loses nothing.&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The choice is between maintaining one implementation—the CLI plus cron, launchd, or Task Scheduler, with one task name and three verification gates—and maintaining two, one of which rests on naming collisions, three storage layers, and a hidden &lt;code&gt;cwd&lt;/code&gt;. We choose the former. This also matches the pattern used by the other adapters: Codex, OpenClaw, and WorkBuddy use their host&apos;s scheduler because those schedulers are &lt;strong&gt;stable APIs&lt;/strong&gt;. Claude Desktop&apos;s is not. Scheduled Tasks are still marked Beta and may change at any time.&lt;/p&gt;
&lt;h2&gt;Trade-off (Explicitly Accepted)&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;If a user has only Claude Desktop and not the Claude Code CLI&lt;/strong&gt;, installing memU requires two additional steps:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Install the standalone CLI with one command: &lt;code&gt;irm https://claude.ai/install.ps1 | iex&lt;/code&gt;, &lt;code&gt;winget install Anthropic.ClaudeCode&lt;/code&gt;, or &lt;code&gt;npm install -g @anthropic-ai/claude-code&lt;/code&gt;. The MSIX bundle included with Desktop does not count because it is not on &lt;code&gt;PATH&lt;/code&gt; and is not visible to a bare process.&lt;/li&gt;
&lt;li&gt;Configure headless authentication using &lt;code&gt;claude setup-token&lt;/code&gt; to obtain &lt;code&gt;CLAUDE_CODE_OAUTH_TOKEN&lt;/code&gt;, or set &lt;code&gt;ANTHROPIC_API_KEY&lt;/code&gt;. The Desktop login is not visible to the CLI; see #538.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;For users who already have the CLI, a verification gate decides whether setup is needed: if &lt;code&gt;claude -p &apos;ping&apos;&lt;/code&gt; succeeds in a bare shell, skip these steps; otherwise, guide the user through &lt;code&gt;setup-token&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;If Desktop&apos;s native scheduling later becomes stable and fully documented—particularly if the same-name split is removed and an out-of-session registration path is provided—we can reconsider it as an optional optimization for Desktop users. Even then, the criterion must be persistence verified on disk, not the tool name.&lt;/p&gt;
&lt;h2&gt;Related&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/NevaMind-AI/memU/issues/538&quot;&gt;#538&lt;/a&gt;: bridging requires a standalone &lt;code&gt;claude&lt;/code&gt; executable on &lt;code&gt;PATH&lt;/code&gt; that supports headless authentication (execution-layer fix)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/NevaMind-AI/memU/issues/539&quot;&gt;#539&lt;/a&gt;: the bridging guide lacks a Windows Task Scheduler path (execution-layer fix)&lt;/li&gt;
&lt;li&gt;#514 (closed; the starting point of this series)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I will add a link after publishing the detailed testing notes on the three storage layers, the A/B comparison, the registry-overwrite timeline, and measurements of scheduling ticks.&lt;/p&gt;
</content:encoded></item><item><title>RRF vs. Hybrid Search: How Should Time-Based Retrieval Be Blended, and How Does It Fit Project and Companion Scenarios?</title><link>https://xnnehang.top/en/posts/RRF-vs-Hybrid-Search/</link><guid isPermaLink="true">https://xnnehang.top/en/posts/RRF-vs-Hybrid-Search/</guid><description>A discussion inspired by MoeChat about RRF and Hybrid Search: how should time retrieval participate in hybrid retrieval, how should it adapt across scenarios, and where are the boundaries between wikimem and XnneHangLab?</description><pubDate>Tue, 21 Jul 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;img src=&quot;../../assets/img/covers/PixPin_2026-07-21_12-26-10.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;:::note
This continues the discussion in [[MoeChat: How AI Characters Remember You and Feel Emotions]].&lt;/p&gt;
&lt;p&gt;At the time, we thought the time-based retrieval proposed by MoeChat was interesting and could be internalized into our own memory framework. This article analyzes a concrete approach and fills in some NLP knowledge along the way.
:::&lt;/p&gt;
&lt;h2&gt;Plain-Language Summary&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;This is the quick version. If you prefer my usual question-and-answer style, skip this section. We will discuss more there.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;There is too little space in this article for my own conclusions, so I will summarize plainly. If you are short on time, this section is enough.&lt;/p&gt;
&lt;p&gt;Hybrid Search specifically means combining keyword matching with semantic-similarity matching. It usually combines their scores through weighted fusion, and that weight is a manually chosen value rather than something computed automatically.&lt;/p&gt;
&lt;p&gt;RRF is a ranking-fusion method. It cares only about rank, not score. RRF can also fuse Hybrid Search results, but there is a problem: it does not care about the actual scores. From RRF&apos;s perspective, first place beating second by 150 points and first place beating second by 2 points make no difference.&lt;/p&gt;
&lt;p&gt;It is like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;queue_1 = [&quot;docs2&quot;, &quot;docs1&quot;,&quot;docs3&quot;,&quot;docs4&quot;]
queue_2 = [&quot;docs3&quot;, &quot;docs2&quot;, &quot;docs1&quot;,&quot;docs4&quot;]

rrf_index = [&quot;docs2&quot;, &quot;docs3&quot;, &quot;docs1&quot;, &quot;docs4&quot;]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It is a way of ranking that intuition alone can understand. The algorithm matters less.&lt;/p&gt;
&lt;p&gt;Another question is whether time retrieval should become a third route.&lt;/p&gt;
&lt;p&gt;Here, we answer no.&lt;/p&gt;
&lt;p&gt;If it became three parallel routes, we would have to introduce RRF as the fusion ranking.&lt;/p&gt;
&lt;p&gt;That brings many problems. Scores become indices, and we lose the actual sense of distance between documents.&lt;/p&gt;
&lt;p&gt;Also, RRF always introduces a systemic bias from the third, time-based route. If the query is time-related, it over-elevates time-related resources. If the query is not time-related, it always introduces noise because the time route always has an RRF rank. One route may not feel significant, but it is still harmful. Imagine ten or twenty routes, with only two or three active each time: the noise brought in by RRF would hide the information that truly matters.&lt;/p&gt;
&lt;p&gt;In the end, we considered a gate plus a decay term. As for the specific decay and how to reduce total latency in the concrete chain, we will only know after implementing the ADR in wikimem.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;We also discuss some less concrete things here.&lt;/p&gt;
&lt;p&gt;Memory structures, diary formats—you do not need to care about those. Even I do not care now. It was only a process of clarifying frameworks and application boundaries, and of sorting out companion and project scenarios once more. Maybe I will never read it again, because it will become my project&apos;s structure. If I need to refine it later, I will return here, draw out new questions, and discuss them again. That is all. I enjoy the process of moving from chaotic confusion to unified clarity; for me, the process of recording matters more than the recorded conclusion.&lt;/p&gt;
&lt;h2&gt;I Know Little, but Have Many Questions&lt;/h2&gt;
&lt;p&gt;In [[MoeChat: How AI Characters Remember You and Feel Emotions]], we promised to learn a little about concrete designs for multi-route hybrid retrieval.&lt;/p&gt;
&lt;p&gt;What I know now is limited to a few names: Hybrid Search and RRF ranking fusion. I know Hybrid Search combines keyword matching and semantic similarity. I know that when fusing scores, comparable weighted scores must be normalized, which is complicated, while RRF only cares about rank and is simple and forceful. It suits methods whose scores cannot be combined.&lt;/p&gt;
&lt;p&gt;But I wonder whether Hybrid Search and RRF differ fundamentally. More precisely, Hybrid Search generally seems not to choose RRF for fusion. Why not? What performance loss or disastrous effects would forcing RRF onto Hybrid Search bring? Would originally interpretable semantic scores be forced into indices? What would that cause?&lt;/p&gt;
&lt;p&gt;Then we will look at adding time beyond semantics and vectors, as we considered in MoeChat. But because time is a ranking problem without a concrete score, it seems we could only use RRF.&lt;/p&gt;
&lt;p&gt;We will also discuss whether directly fusing three routes with RRF is preferable to using time as a gate.&lt;/p&gt;
&lt;p&gt;Forcing time into Hybrid Search creates problems. For example, if a time window contains many memory records and the user only asks &lt;code&gt;Do you remember what I usually ate for lunch last week?&lt;/code&gt;, the topic is narrow.&lt;/p&gt;
&lt;p&gt;If we force the three routes together, after retrieving the time range we must run Hybrid Search again. Otherwise, there is too much memory. Even one evening&apos;s memories cannot all be stuffed into context, much less an entire week.&lt;/p&gt;
&lt;p&gt;But running Hybrid Search again reveals structural redundancy: one Hybrid Search across all time and one Hybrid Search across a selected time range. In MoeChat, does it directly recall all diary content in a time range with no second filter? This needs confirmation. Is it because LTM contains too little content for a second filter to be necessary, or is there another idea?&lt;/p&gt;
&lt;p&gt;:::note[Korewaxnne]
Confirmed, looking back at the breakdown in [[MoeChat: How AI Characters Remember You and Feel Emotions]]:&lt;/p&gt;
&lt;p&gt;MoeChat&apos;s LTM retrieval is &lt;strong&gt;pure gating with no second-stage selection&lt;/strong&gt;. The concrete process is:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;A user message first goes through &lt;code&gt;jioNLP&lt;/code&gt; to extract time expressions such as “yesterday” and “last Friday,” then parse them into a timestamp range.&lt;/li&gt;
&lt;li&gt;A &lt;strong&gt;binary search&lt;/strong&gt; over sorted timestamps using &lt;code&gt;bisect_left/bisect_right&lt;/code&gt; locates every memory in that range in O(log n).&lt;/li&gt;
&lt;li&gt;Optional: if &lt;code&gt;enableLongMemorySearchEnhance&lt;/code&gt; is enabled, cosine similarity filters once using a 0.32 threshold, but this is only filtering, not an independent semantic-retrieval route.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;If the user message contains no time expression, LTM does not participate at all&lt;/strong&gt; and the function returns empty.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;So your guess was right: it recalls &lt;strong&gt;all&lt;/strong&gt; memories inside the time window without a second Hybrid Search. The reason is also what you thought—the LTM writes fact-like JSONL entries by day, with only a few entries per day, so one entire day fits into context. It does not avoid a second Hybrid Search because of some design philosophy; &lt;strong&gt;the data volume is simply small enough that it does not need one.&lt;/strong&gt;
:::&lt;/p&gt;
&lt;p&gt;A better derivation, then, is to make time a gate: only when the user strongly activates a specific time should it define a broad time range, and then Hybrid Search runs within that range. But this also creates a problem: Hybrid Search cannot work independently, and time processing might take a while because it is still unclear whether time reasoning should depend on an LLM.&lt;/p&gt;
&lt;p&gt;Perhaps this must begin from purpose. For MoeChat, the original purpose of LTM and time retrieval is simple: to let the model answer concrete questions such as “What did I eat the night before last?” In its application setting, LTM writes fact-like records, which suit this kind of retrieval, and there are not many of them.&lt;/p&gt;
&lt;p&gt;In my desktop-companion scenario, I would directly use three-route hybrid retrieval, with simple RRF fusion—not for a sophisticated reason, but so time retrieval can work independently like MoeChat&apos;s. And I have a simple mind; RRF suits my taste.&lt;/p&gt;
&lt;h2&gt;Hybrid Search and RRF: Choosing a Two-Route Fusion Method&lt;/h2&gt;
&lt;h3&gt;The relationship between Hybrid Search and RRF&lt;/h3&gt;
&lt;p&gt;Does Hybrid Search have a particular relationship to RRF? Is it as I understand it: Hybrid Search can choose either RRF or weighted fusion as its method?&lt;/p&gt;
&lt;p&gt;:::note[Korewaxnne]
&lt;strong&gt;Yes, exactly that relationship.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Hybrid Search is a &lt;strong&gt;strategy&lt;/strong&gt;: “I use keyword search and semantic search at the same time, then combine the results.”&lt;/p&gt;
&lt;p&gt;RRF is &lt;strong&gt;one fusion method&lt;/strong&gt;: “How do I combine the two result sets?”&lt;/p&gt;
&lt;p&gt;So Hybrid Search needs to choose a fusion method. There are two common ones:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Weighted Score Fusion&lt;/strong&gt;: normalize both route scores, then calculate a weighted sum. For example, &lt;code&gt;0.7 × semantic score + 0.3 × keyword score&lt;/code&gt;. You can tune the weight and explain why a result came first.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;RRF (Reciprocal Rank Fusion)&lt;/strong&gt;: ignore scores and use only rank. The formula is &lt;code&gt;1/(k + rank)&lt;/code&gt;, then adds reciprocal ranks from each route. It is simple and forceful, and needs no normalization.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;As an analogy: Hybrid Search is “I want to travel to my destination,” while RRF and weighted fusion are “take the bus or a taxi.” Both get you there, with different trade-offs.
:::&lt;/p&gt;
&lt;p&gt;Wait, are those weighted-fusion weights not calculated automatically? Are they set manually?&lt;/p&gt;
&lt;p&gt;:::note[Korewaxnne]
&lt;strong&gt;They are set manually, not calculated automatically.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Weights in weighted fusion—semantic 0.7 and keywords 0.3, for example—are &lt;strong&gt;hyperparameters&lt;/strong&gt;, like a learning rate. You choose them and tune them through experiments.&lt;/p&gt;
&lt;p&gt;The usual approach is to take annotated queries plus expected results, run different weight combinations, see which produces the best retrieval metrics such as nDCG or MRR, then use that one. There is no gradient descent optimizing the value behind the scenes.&lt;/p&gt;
&lt;p&gt;This is also an advantage of RRF: it requires no weight tuning. You can use it immediately. Weighted fusion needs an evaluation set to tune reliable weights; without one, you can only guess by feel.
:::&lt;/p&gt;
&lt;p&gt;Why would it not use RRF? If RRF is forcibly applied to Hybrid Search, what performance loss or disastrous impact follows? What if interpretable semantic scores are forced into indices?&lt;/p&gt;
&lt;p&gt;:::note[Korewaxnne]
&lt;strong&gt;Hybrid Search can use RRF, but in most scenarios it is not worthwhile because it throws away score information for no reason.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Keyword search through BM25 and semantic search through cosine similarity both assign every result a &lt;strong&gt;concrete score&lt;/strong&gt;. Those scores matter: the gap between cosine 0.95 and 0.60 conveys far more than “first versus second.”&lt;/p&gt;
&lt;p&gt;If you use RRF, you throw away every score and retain only rank. Specifically, you lose:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Score-gap information.&lt;/strong&gt; In RRF, semantic first place at 0.95 and second at 0.94 is exactly the same as first at 0.95 and second at 0.30: both are “first versus second.” But in the latter case, second place is not relevant at all.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The ability to tune weights.&lt;/strong&gt; With weighted fusion, you can say “semantics contributes 70%, keywords 30%” and tune by scenario. RRF cannot offer that granularity of control.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Explainability.&lt;/strong&gt; Under weighted fusion, you can say “this was ranked first because its semantic score was 0.92 and its keyword score was 0.85.” Under RRF, you can only say “its combined ranks were highest.”&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The conclusion is simple: &lt;strong&gt;when both routes have scores, weighted fusion is better&lt;/strong&gt; because it retains more information. RRF&apos;s natural setting is one where a route has no comparable scores, such as a time dimension, which has ordering but no relevance score.
:::&lt;/p&gt;
&lt;p&gt;RRF does indeed ignore score and gap information. But it feels clean for inputs that have no scores themselves.&lt;/p&gt;
&lt;p&gt;You can read &lt;a href=&quot;https://github.com/NevaMind-AI/memU/tree/main/docs/adr&quot;&gt;memU ADR&lt;/a&gt;, especially ADR 0006, 0007, and 0008. Our retrieve is already implemented, though reading the source is the same.&lt;/p&gt;
&lt;p&gt;Later it unexpectedly updated 9, 10, and 11 as well. That is not your responsibility; I will follow up later in [[What Is memU? Let&apos;s Break It Down (An Ongoing Series)|What Is memU? Let&apos;s Break It Down]].&lt;/p&gt;
&lt;p&gt;:::note[Korewaxnne]
&lt;strong&gt;memU uses weighted score fusion with min-max normalization, not RRF.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;According to ADR-0007: cosine embedding scores and BM25 keyword scores are each min-max normalized, then fused into one ranking. This is the classic weighted-score-fusion route.&lt;/p&gt;
&lt;p&gt;But the source code currently runs vector-only cosine similarity; the BM25 route has not been implemented yet, so hybrid search remains at the design stage.
:::&lt;/p&gt;
&lt;h2&gt;Adding a Time Dimension: The Challenges and Trade-Offs of Three-Route Retrieval&lt;/h2&gt;
&lt;p&gt;Now let us consider a harder problem.&lt;/p&gt;
&lt;p&gt;If I add MoeChat-style time as a third route, it disrupts ADR 0007&apos;s established score fusion and seems to force RRF.&lt;/p&gt;
&lt;p&gt;We can analyze this by application scenario, beginning simply with project scenarios and long-term companion desktop-companion scenarios.&lt;/p&gt;
&lt;p&gt;Let us analyze three methods:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Run all three routes in parallel and fuse everything with RRF.&lt;/li&gt;
&lt;li&gt;Run all three routes in parallel and do two things at once: RRF plus the original weighted fusion. If the time rank and other route ranks differ enough under RRF, use time directly; otherwise, ignore time and output the original result.&lt;/li&gt;
&lt;li&gt;Treat time as a gating unit. Time defines the candidate-memory range, then Hybrid Search runs normally within it.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This feels difficult, so I will ask Teacher Fable. Teacher Fable, please analyze a better approach too if one exists.&lt;/p&gt;
&lt;p&gt;:::note[Fable]
The conclusion first: &lt;strong&gt;c is the main path, but it lacks half a piece; b can be discarded directly; and the “time working independently” that a wants is actually a degenerate case of c, so there is no need to retain three-way voting.&lt;/strong&gt;&lt;/p&gt;
&lt;h3&gt;See the problem clearly first: time is not the same kind of signal as the other two routes&lt;/h3&gt;
&lt;p&gt;Semantic and keyword scores answer “&lt;strong&gt;is this memory about this subject?&lt;/strong&gt;” That is relevance, which can be voted on. Time answers “&lt;strong&gt;is this memory inside the range being asked about?&lt;/strong&gt;” That is a constraint. A memory outside “the night before last” is not “somewhat irrelevant”; it is &lt;strong&gt;wrong&lt;/strong&gt;. Constraints should filter, not vote.&lt;/p&gt;
&lt;p&gt;There is another subtler asymmetry. BM25 and vector candidate lists are &lt;strong&gt;conditioned on the query&lt;/strong&gt;: if content does not match, it has no score and cannot enter the list, so these routes quiet down by themselves when the query is irrelevant. Time is different: every memory has a timestamp, so the time route &lt;strong&gt;can always produce a complete ranking&lt;/strong&gt; no matter what the query asks. A voter that always has a vote in RRF creates systemic bias.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;That bias should not exist. So simple all-RRF is wrong: it both loses the precision and gap information of concrete scores and permanently introduces noise.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;a. All three routes through RRF—not disastrous, but needlessly imprecise&lt;/h3&gt;
&lt;p&gt;There are two problems:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;For &lt;strong&gt;queries without time intent&lt;/strong&gt;, such as “What anime do I like most?”, the time route degrades into a pure recency vote, elevating new but irrelevant memories. In project scenarios that is pure loss; in companion scenarios it barely counts as a freshness preference, at the cost of precision for every query.&lt;/li&gt;
&lt;li&gt;For &lt;strong&gt;queries with time intent&lt;/strong&gt;, such as “What did I eat the night before last?”, the time route must first parse “the night before last” into a range before it can rank by closeness to the target. In other words, a does not eliminate time parsing; you need the parser anyway. Once you have a range, voting is a detour: voting cannot guarantee the winner lies in the range. A memorable dinner from three weeks ago may semantically overwhelm an ordinary dinner from the night before last, and RRF cannot stop it. Answering “what I ate the night before last” incorrectly is a factual failure and the kind that damages trust most in a desktop companion.&lt;/li&gt;
&lt;/ol&gt;
&lt;blockquote&gt;
&lt;p&gt;A very good correction. If we have already obtained the range, it should not enter the voting electorate at all.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;b. Dual fusion plus divergence trigger—discard directly&lt;/h3&gt;
&lt;p&gt;The trigger condition measures the wrong thing. Large differences between time ranking and semantic ranking are not a signal but &lt;strong&gt;the norm&lt;/strong&gt;: novelty and relevance are naturally unrelated, so the lists almost always differ. That trigger either stays open or detects nothing. Evidence for whether time should be used lives &lt;strong&gt;in the query&lt;/strong&gt;—words such as “last week” and “the day before yesterday”—not in divergence between result lists. Inferring query intent from result divergence uses the wrong sensor for the right decision.&lt;/p&gt;
&lt;p&gt;It also requires maintaining two fusion methods plus a divergence threshold that is harder to tune than fusion weights. The original reason for choosing RRF was to avoid tuning parameters; b gives that benefit back.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;This path not only looks awkward but introduces a very difficult hyperparameter: when exactly is the gap too large? That would make the system weak.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;c. Time gating—the direction is right, and both concerns have answers&lt;/h3&gt;
&lt;p&gt;In engineering terms, c is standard &lt;strong&gt;metadata pre-filtering&lt;/strong&gt; in a vector database: &lt;code&gt;WHERE ts BETWEEN ...&lt;/code&gt;. ADR 0007&apos;s fusion formula does not need a single change; it simply runs on a filtered candidate set. Your two earlier concerns have solutions:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;“Does time parsing need an LLM, and will it be slow?”&lt;/strong&gt; A desktop companion already runs an LLM each turn. Make retrieval a tool call and have the model produce &lt;code&gt;time_range&lt;/code&gt; as an argument along the way, making parse cost effectively free. Common expressions—yesterday, the day before yesterday, last week, a date—can take a regex fast path. Expressions the regex cannot handle, such as “the day we last argued,” can only be handled by an LLM anyway: that is event anchoring, requiring retrieval of that event, its date, and then a window around it. This natural two-hop gate is not expressible as voting.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;“Under a gate, time cannot work independently.”&lt;/strong&gt; A pure time query, such as “What happened the night before last?”, becomes: gate out the range plus an empty semantic query, then degrade into taking the top N memories in the range by time. That is MoeChat&apos;s behavior. As you observed, it is just gating; there was never a three-route fusion waiting to be copied. MoeChat can recall an entire section because its LTM is small. Your memory is larger, so Hybrid Search still runs inside the range—and that is exactly c.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Add one fallback and it is complete: when a parsed window retrieves nothing, automatically broaden it by ±1 day or use fuzzy boundaries, so one parsing mistake does not become “I do not remember.”&lt;/p&gt;
&lt;h3&gt;But c lacks half a piece: time has two roles&lt;/h3&gt;
&lt;p&gt;Time does two different jobs in retrieval:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Explicit time references&lt;/strong&gt;, such as “the night before last” or “last week at noon,” are hard filters—gates—as described above.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Implicit freshness preference&lt;/strong&gt;, when the user mentions no time but what was discussed yesterday should surface more readily than something from three months ago. This does not need a third route. Add a small weighted time-decay term to the existing score fusion, for example $e^{-\Delta t/\tau}$. It has a score, can be normalized, and can be tuned, so it is fully compatible with ADR 0007&apos;s score fusion without changing to RRF.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The final shape is: &lt;strong&gt;gate for role 1, decay for role 2, and the unchanged two-route weighted fusion&lt;/strong&gt;. The concept of a “third route” disappears completely. Time is never really a retrieval route because it cannot answer what a memory is about; it can only constrain a range or apply a small preference. RRF remains useful, but its proper setting is several genuine rankers with incomparable scores. Time is not a ranker, so it does not belong here.&lt;/p&gt;
&lt;h3&gt;Closing by scenario&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Project scenarios:&lt;/strong&gt; even the gate can be simpler. Time in project memory is often really version: “what is the latest decision?” is solved by replacement relations at write time plus a recency tiebreak at read time, not by time retrieval. And the caller is already an agent; when a time query really occurs, let it pass an optional &lt;code&gt;time_range&lt;/code&gt; parameter. &lt;strong&gt;Do not perform intent detection inside the memory system when the query-understanding caller already did it.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Desktop-companion scenarios:&lt;/strong&gt; time is a first-class concern, with one lethal detail: contextual memory contains many semantically near-duplicate events—you ate lunch fifty times, and fifty memories are nearly identical semantically. &lt;strong&gt;The only thing that distinguishes the lunch on last Wednesday is time.&lt;/strong&gt; The more near duplicates there are, the less reliable a soft preference or vote becomes, and the more necessary a hard constraint is. “What do I usually eat for lunch during the week?” runs cleanly through c: window equals last week, query equals lunch, top-k inside the window, then the LLM summarizes the pattern.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Method&lt;/th&gt;
&lt;th&gt;Project scenario&lt;/th&gt;
&lt;th&gt;Desktop-companion scenario&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;a. Three-route RRF&lt;/td&gt;
&lt;td&gt;✗ Recency pollution; pure loss&lt;/td&gt;
&lt;td&gt;△ It runs, but “the night before last” questions are unreliable&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;b. Dual fusion plus trigger&lt;/td&gt;
&lt;td&gt;✗ The trigger measures the wrong thing&lt;/td&gt;
&lt;td&gt;✗ Same&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;c. Gating&lt;/td&gt;
&lt;td&gt;✓ Can simplify to an optional filter parameter&lt;/td&gt;
&lt;td&gt;✓ Main path&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;c plus decay&lt;/td&gt;
&lt;td&gt;✓ A recency tiebreak is enough&lt;/td&gt;
&lt;td&gt;✓✓ Recommended form&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;One-sentence version: &lt;strong&gt;explicit time filters, implicit time decays, and time is never a third route.&lt;/strong&gt;
:::&lt;/p&gt;
&lt;h2&gt;Design Implementation: Time Fast Paths and Memory Structure&lt;/h2&gt;
&lt;p&gt;:::note[For readers passing by]
Up to the scenario table above, these are general conclusions worth taking away. What follows is a design workshop for our own projects, wikimem and XnneHangLab. It needs the context of [[MoeChat: How AI Characters Remember You and Feel Emotions]]; if you do not know that, skipping the second half loses no general knowledge.
:::&lt;/p&gt;
&lt;p&gt;But I still hope the fast path for time retrieval can always activate and work independently, with intent recognition made into a tool call.&lt;/p&gt;
&lt;p&gt;This involves quite a lot. You can look at:&lt;/p&gt;
&lt;p&gt;::github{repo=&quot;XnneHangLab/wikimem&quot;}&lt;/p&gt;
&lt;p&gt;::github{repo=&quot;XnneHangLab/XnneHangLab&quot;}&lt;/p&gt;
&lt;h3&gt;Time fast path: regex and intent recognition as parallel tracks&lt;/h3&gt;
&lt;p&gt;I think wikimem should own a MoeChat-like fast time-retrieval path:&lt;/p&gt;
&lt;p&gt;:::note
Several alternatives:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https://github.com/scrapinghub/dateparser&quot;&gt;dateparser&lt;/a&gt;&lt;/strong&gt; supports more than 200 languages, including Chinese. It is rule-based and lightweight: &lt;code&gt;pip install dateparser&lt;/code&gt;, then &lt;code&gt;dateparser.parse(&quot;昨天下午&quot;)&lt;/code&gt; returns a datetime directly. It needs no jioNLP NER step; it works in one step.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https://github.com/arrow-py/arrow&quot;&gt;arrow&lt;/a&gt;&lt;/strong&gt; plus handwritten regex: if time-expression patterns are enumerable—“yesterday,” “the day before yesterday,” “last week X,” “X days ago”—regex matching plus arrow&apos;s &lt;code&gt;shift()&lt;/code&gt; can calculate offsets. A dozen lines can cover MoeChat&apos;s scenario with zero dependency overhead.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https://github.com/zhanzecheng/Time_NLP&quot;&gt;TimeNLP&lt;/a&gt;&lt;/strong&gt; is a small library dedicated to Chinese time semantics, much lighter than jioNLP and focused only on time.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The most pragmatic choice is actually the second one. MoeChat needs to recognize only a dozen or so patterns—yesterday, the day before yesterday, last week X, X days ago, X month X day. Regex plus time-offset calculations are enough; it does not need a general NLP library.
:::&lt;/p&gt;
&lt;p&gt;This was the plan we came up with last time.&lt;/p&gt;
&lt;p&gt;I think wikimem should have a fast path like MoeChat&apos;s. Intent recognition and time analysis for expressions that a simple regex cannot hit could become a Tool Calling capability integrated into XnneHangLab. I do not want to mix responsibilities.&lt;/p&gt;
&lt;p&gt;What does intent recognition add? It handles vague time expressions beyond a simple regex. I want us to focus on implementing the simple regex solution, then hand complex work to an intent-recognition tool call.&lt;/p&gt;
&lt;h3&gt;Memory structure: the boundary between diaries and wikis&lt;/h3&gt;
&lt;p&gt;There is also the question of memory structure. Along a timeline, MoeChat remembers only factual contextual memories, while preferences, personas, and so on are separate structures.&lt;/p&gt;
&lt;p&gt;But as I wrote in [[MoeChat: How AI Characters Remember You and Feel Emotions]], LTM and CoreMemory have somewhat unclear boundaries. That makes it look uncomfortable.&lt;/p&gt;
&lt;p&gt;memU&apos;s early six memory types also make memorize very heavy. What do you recommend?&lt;/p&gt;
&lt;p&gt;How should we store our memories? As JSONL fact fragments, or lively Markdown diaries written by a model?&lt;/p&gt;
&lt;p&gt;More accurately, how do we define memory? What belongs in memory that can be recalled by time? Should it include every memory?&lt;/p&gt;
&lt;p&gt;Should we use fact-only diaries like MoeChat&apos;s only for time recall? But are records of a model&apos;s emotions then unimportant? Emotion creates personality. If there are only facts and no context, there is no soul.&lt;/p&gt;
&lt;p&gt;And since our wikimem supports both embeddings and zero-embedding mode, we need to reserve embedding storage for every retrievable memory. The embedding needs what information—dimension, embedding-model name? If names differ, should it warn users and ask them to rebuild the whole memory database?&lt;/p&gt;
&lt;p&gt;What belongs in SQLite, and what belongs in Markdown?&lt;/p&gt;
&lt;p&gt;Should we replace MoeChat&apos;s JSONL with SQLite for higher performance, then build a front-end system in XnneHangLab to visualize memory data, so users can browse it by time and search it by content?&lt;/p&gt;
&lt;p&gt;But perhaps wikimem itself should provide this because wikimem is a framework. At least it should avoid insisting on a CLI, like a yutto serve RPC redesign, and expose data interfaces so other applications can wrap it. The transport protocol also needs planning.&lt;/p&gt;
&lt;p&gt;At the same time, the Markdown diary system needs management too.&lt;/p&gt;
&lt;h2&gt;Dividing Responsibilities Between Framework and Application&lt;/h2&gt;
&lt;p&gt;Teacher Fable, please help. We may need to update the ADRs for wikimem and XnneHangLab. We need to decide what belongs to the framework and what belongs to the application.&lt;/p&gt;
&lt;p&gt;:::note[Fable]
I read both repositories: wikimem&apos;s current state, XnneHangLab&apos;s ADR-0001 through ADR-0003, and the wikimem plugin. First the general principle, then the parts.&lt;/p&gt;
&lt;h3&gt;You have already drawn the boundary&lt;/h3&gt;
&lt;p&gt;ADR-0001 has a hard constraint: “retrieve makes 0 LLM calls; memorize makes ≤ 1 asynchronous LLM call, initiated by the host.” Extending that rule gives the entire answer:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The framework handles deterministic mechanisms—rules, mathematics, and I/O. Anything requiring model judgment belongs to the application.&lt;/strong&gt; Embeddings are the only exception, but they are injected as pluggable, optional, and gracefully degradable; wikimem&apos;s zero-core-dependency nature is worth preserving.&lt;/p&gt;
&lt;p&gt;Use that line to divide every question below.&lt;/p&gt;
&lt;h3&gt;The time fast path belongs to wikimem, correctly&lt;/h3&gt;
&lt;p&gt;Design one parameter with two sources:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;index.retrieve(query, time_range=None)
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;No &lt;code&gt;time_range&lt;/code&gt; given:&lt;/strong&gt; wikimem runs an internal regex fast path for yesterday, the day before yesterday, last week X, X days ago, and X month X day. Pure stdlib—&lt;code&gt;re&lt;/code&gt; plus &lt;code&gt;datetime&lt;/code&gt;—is enough. Do not introduce dateparser; a general library for “200+ languages” adds a dependency and violates the zero-dependency constraint. Arrow is unnecessary too; &lt;code&gt;timedelta&lt;/code&gt; can do the calculation.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;time_range&lt;/code&gt; given:&lt;/strong&gt; use it directly and skip regex. This is the application-side outlet for an intent-recognition tool call. An LLM handles expressions such as “the day we last argued” that regex can never reach, including two-hop event-anchor queries, but it finally produces the same structured parameter.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The two paths converge on the same parameter, so responsibilities do not blur: &lt;strong&gt;regex is the framework&apos;s floor; the LLM is the application&apos;s ceiling; there is no third parser between them.&lt;/strong&gt;&lt;/p&gt;
&lt;h3&gt;But fill one missing piece first: wikimem has no timeline yet&lt;/h3&gt;
&lt;p&gt;The code shows that wikimem has only a &lt;strong&gt;state layer&lt;/strong&gt;—category/item wiki. It stores &lt;code&gt;ts&lt;/code&gt;, but retrieval never uses it; there is no time filtering or decay. The earlier gating proposal has nothing to gate yet. &lt;strong&gt;The event-stream primitive is missing.&lt;/strong&gt; So memory structure and time retrieval are the same problem.&lt;/p&gt;
&lt;h3&gt;Memory structure: two primitives and one boundary rule&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Diary, the event stream:&lt;/strong&gt; append-only, one file per day, time as the primary axis. This is a new primitive.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Wiki, the state layer:&lt;/strong&gt; existing category/items, content as the primary axis, editable.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The boundary rule is one sentence: &lt;strong&gt;what happened goes in the diary; what is true now goes in the wiki.&lt;/strong&gt; MoeChat&apos;s LTM and CoreMemory are unclear because they divide by “importance” or “permanence,” which are continuous and changing and cannot make a clean boundary. “Event versus state” is discrete: a memory either has the property “when did it happen?” or it does not. The same event can appear in both: “On July 21, he said he changed jobs and sounded excited” in the diary, while the &lt;code&gt;work&lt;/code&gt; wiki entry updates as state. They do not conflict.&lt;/p&gt;
&lt;p&gt;Do not copy memU&apos;s six memory types into the framework. Those are content strategies for the state layer and belong in extraction prompts; your categories are already free. The six types make memorize heavy because each gets a separate LLM run. ADR-0001&apos;s “≤ 1 call” has already avoided that pit.&lt;/p&gt;
&lt;h3&gt;Where emotions go: split them into two things&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Emotions in events&lt;/strong&gt; belong in the diary. A diary entry should be a lively short segment written by a model—scene, emotion, and facts together. Your &lt;code&gt;diary_writing&lt;/code&gt; skill prompt already does this. That is where the “soul” lives. It also answers JSONL fragments versus lively Markdown: &lt;strong&gt;the diary should be lively Markdown and facts should go in the wiki. You need both, not one or the other.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Current emotional state&lt;/strong&gt;, such as MoeChat&apos;s &lt;code&gt;emotion_state.json&lt;/code&gt; valence/arousal model, is not memory. It changes every turn and does not need retrieval; it remains application runtime state.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;What can be recalled by time? Only the diary. The wiki is not on a time axis. A future need such as “preferences added last week” can use &lt;code&gt;ts&lt;/code&gt; as a filtering bonus, but it is not the main axis. Having every memory recalled by time is wrong: preferences should not be pulled out by “last week.”&lt;/p&gt;
&lt;h3&gt;Storage: the filename is the time index; do not use SQLite yet&lt;/h3&gt;
&lt;p&gt;Use a Markdown file per day for diaries—&lt;code&gt;diary/2026-07-21.md&lt;/code&gt;, one &lt;code&gt;## HH:MM&lt;/code&gt; entry plus a timestamp comment. The easily overlooked benefit is that &lt;strong&gt;the filename itself is the time index&lt;/strong&gt;. Gating a window means selecting files by date range, O(number of days), zero indexes and zero dependencies. MoeChat&apos;s daily JSONL proves this path. Then run existing BM25/fusion inside the window and the earlier c plan becomes complete.&lt;/p&gt;
&lt;p&gt;SQLite&apos;s problem is not performance; it violates ADR-0001: “there can be no unreadable truth on disk.” Truth must be Markdown. SQLite can at most be a deletable derived cache, alongside &lt;code&gt;vectors.npy&lt;/code&gt;. At the current scale—one desktop companion year is about ten to twenty thousand records—in-memory BM25 plus existing signature layers is milliseconds, so a cache is not needed. &lt;strong&gt;Truth is always Markdown; SQLite is neither truth nor a cache for now. Revisit at one hundred thousand entries, and then use an FTS5 derived cache.&lt;/strong&gt; VectorIndex already leaves room as a Protocol.&lt;/p&gt;
&lt;h3&gt;Embedding metadata: a real gap, but a lighter fix than you expect&lt;/h3&gt;
&lt;p&gt;The current &lt;code&gt;vectors.keys.jsonl&lt;/code&gt; header only stores the vectors file; it records neither model name nor dimension. Your concern is correct. Add &lt;code&gt;{&quot;model&quot;: ..., &quot;dim&quot;: ...}&lt;/code&gt; to the header, then compare it to configuration when opening.&lt;/p&gt;
&lt;p&gt;But a mismatch should not “error and make the user rebuild the whole memory database.” Wikimem&apos;s truth is Markdown, and vectors are only a content-hash-keyed derived cache. &lt;strong&gt;Changing the model means invalidating the cache and incrementally re-embedding as needed.&lt;/strong&gt; There is no database to rebuild. Match existing philosophy: mismatch means a warning, degradation for the current session, and a prompt to run a re-embedding command. Zero-embedding mode is naturally the end of this degraded path.&lt;/p&gt;
&lt;p&gt;And one correction: do not reserve an embedding slot on every memory record. Putting vectors into truth files would destroy readable truth. The existing derived-cache design is right; keep it.&lt;/p&gt;
&lt;h3&gt;serve and front end: the Python API is the contract; everything else is a shell&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;wikimem&apos;s contract is its Python API&lt;/strong&gt;, &lt;code&gt;MemoryStore&lt;/code&gt; and &lt;code&gt;MemoryIndex&lt;/code&gt;. M4 should be a thin-shell layer: both a CLI and &lt;code&gt;[serve]&lt;/code&gt;—HTTP plus JSON as an extra, similar to &lt;code&gt;[embed]&lt;/code&gt;—are skins over the same API. Do not create a transport protocol; HTTP plus JSON and a version are enough. Serve is for out-of-process consumers: other applications and independent browsers.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;XnneHangLab does not need wikimem&apos;s serve&lt;/strong&gt; because it imports in-process already—milliseconds versus memU&apos;s two-second subprocess path. Visualization belongs on its own FastAPI/WebSocket routes.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The visualization UI belongs entirely to the application.&lt;/strong&gt; The framework guarantees data access: list dates, read a day, search, tail the journal. Its file-first design gives a free benefit: Markdown truth means Obsidian or any editor already works as a memory browser. That is enough for debugging; do not build UI in the framework.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Put it into ADRs&lt;/h3&gt;
&lt;p&gt;wikimem currently has no ADR directory; framework decisions are all recorded in XnneHangLab ADRs. Since it is now an independent repository, its decisions should follow the framework. Also confirm whether &lt;code&gt;packages/wikimem&lt;/code&gt; and the separate repository are the same code: the workspace appears to have &lt;code&gt;cli.py&lt;/code&gt; while the separate repository does not. If they are two copies, they are already drifting.&lt;/p&gt;
&lt;p&gt;(Postscript before release: I checked. It is not drift—the standalone repository checkout is merely four commits behind. The upstream already merged the zero-dependency CLI in &lt;a href=&quot;https://github.com/XnneHangLab/wikimem/pull/12&quot;&gt;wikimem#12&lt;/a&gt;, and both are the same codebase.)&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Owner&lt;/th&gt;
&lt;th&gt;ADRs to write&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;wikimem&lt;/td&gt;
&lt;td&gt;Diary primitive: daily Markdown, append-only; retrieval gets &lt;code&gt;time_range&lt;/code&gt; plus stdlib-only regex fast path; optional recency-decay term enters fusion; vector cache records model/dimension and degrades on mismatch; M4 redefines CLI/serve as two thin shells.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;XnneHangLab&lt;/td&gt;
&lt;td&gt;Time-intent-recognition tool call for vague time and event anchors to &lt;code&gt;time_range&lt;/code&gt;; elevate &lt;code&gt;diary_writing&lt;/code&gt; into a formal memorize policy—when to write, what to write, and its voice; keep emotion state as application runtime; memory-visualization front end through its own routes.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;One-sentence version: &lt;strong&gt;the framework manages deterministic mechanisms; the application manages costly judgment; what happened goes in the diary, what is true now goes in the wiki; truth is always Markdown, and everything else is a deletable cache or replaceable shell.&lt;/strong&gt;
:::&lt;/p&gt;
&lt;h2&gt;Postscript&lt;/h2&gt;
&lt;p&gt;Thank you, Teacher Fable. While clarifying the relationship between RRF and Hybrid Search, it also made clear where wikimem should go and what XnneHangLab should own. I opened two PRs:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/XnneHangLab/XnneHangLab/pull/499&quot;&gt;XnneHangLab#499&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/XnneHangLab/wikimem/pull/14&quot;&gt;wikimem#14&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>MoeChat: How AI Characters Remember You and Feel Emotions</title><link>https://xnnehang.top/en/posts/moechat_ltm/</link><guid isPermaLink="true">https://xnnehang.top/en/posts/moechat_ltm/</guid><description>An in-depth look at how MoeChat builds long-term memory for AI characters, including its time-and-semantic hybrid retrieval—written for people interested in memory systems.</description><pubDate>Wed, 15 Jul 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;img src=&quot;../../assets/img/moechat-beginner-guide/moechat-cover-poster.jpg&quot; alt=&quot;MoeChat cover&quot; /&gt;&lt;/p&gt;
&lt;p&gt;:::note[AI Disclosure]
This article was &lt;strong&gt;almost entirely written by Claude OPUS 4.6&lt;/strong&gt;, with Xnne reviewing it. Want to read the human-written parts? Skip directly to the Q&amp;amp;A.&lt;/p&gt;
&lt;p&gt;Honestly, though, Claude did a much better job than Xnne at the architecture breakdown 😅&lt;/p&gt;
&lt;p&gt;And this is not the end—it is only the beginning. It gave me many ideas and can be treated as a TODO. The breakdown felt great. I had honestly been a little afraid of MoeChat; its code is genuinely messy, and I had tried reading it many times without getting through. But Claude suffered on my behalf.
:::&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;What Is MoeChat?&lt;/h2&gt;
&lt;p&gt;::github{repo=&quot;AlfreScarlet/MoeChat&quot;}&lt;/p&gt;
&lt;p&gt;&amp;lt;iframe src=&quot;https://player.bilibili.com/player.html?bvid=BV1djNdz2Ew2&amp;amp;autoplay=0&amp;amp;page=1&quot; scrolling=&quot;no&quot; border=&quot;0&quot; frameborder=&quot;no&quot; framespacing=&quot;0&quot; allowfullscreen=&quot;true&quot; allow=&quot;fullscreen; picture-in-picture&quot; style=&quot;width: 100%; aspect-ratio: 16 / 9;&quot;&amp;gt;&amp;lt;/iframe&amp;gt;&lt;/p&gt;
&lt;p&gt;MoeChat is an open-source system for creating AI characters that can &lt;strong&gt;remember&lt;/strong&gt; and &lt;strong&gt;feel&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Most chatbots are goldfish—they start from zero in every conversation. MoeChat is different. It gives every character:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Long-term memory&lt;/strong&gt;—a diary system that extracts important content from every conversation, stores it, and automatically recalls it when relevant&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Core memory&lt;/strong&gt;—permanent facts about you, such as your name, preferences, and relationship&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;An emotion engine&lt;/strong&gt;—based on a two-dimensional emotion model, valence plus arousal, with accumulated frustration, emotional-meltdown states, and even hormone-cycle simulation&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It also supports voice—GPT-SoVITS for TTS and FunASR for ASR—but its real core is how it builds a persistent inner world for every character. This article is about that.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;Character Agent: One Folder, One Life&lt;/h2&gt;
&lt;p&gt;Every character lives under &lt;code&gt;data/agents/&amp;lt;name&amp;gt;/&lt;/code&gt;. Everything about them is stored in isolation there:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;data/agents/Chat酱/
├── info.yaml              # personality, system prompt, every feature flag
├── memory/                # long-term memory: daily JSONL files
│   ├── 2025-7-10.jsonl
│   ├── 2025-7-11.jsonl
│   └── ...
├── core_mem.yml           # core memory: permanent facts about the user
├── data_base/             # knowledge base: world-building knowledge
├── emotion_state.json     # persisted emotional state
└── assets/                # avatar images
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;info.yaml&lt;/code&gt; lets you turn each feature on or off:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;settings:
  writeLongMemory: true # write new memories after chatting
  enableLongMemory: true # retrieve memories while chatting
  enableLongMemorySearchEnhance: true # filter with vector similarity
  longMemoryThreshold: 0.32 # cosine-similarity threshold

  enableCoreMemory: false # extract user facts
  enableEmotionSystem: false # enable the emotion engine
  enableEmotionPersist: false # persist emotion across sessions
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Notice that &lt;code&gt;writeLongMemory&lt;/code&gt; and &lt;code&gt;enableLongMemory&lt;/code&gt; are independent: you can write without reading, or read without writing.&lt;/p&gt;
&lt;h3&gt;What do the files look like?&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;info.yaml&lt;/strong&gt;—the character&apos;s “identity card”:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;name: Chat酱
user: 阁下 # how the character addresses you
birthday: &apos;2022-03-17&apos;
height: &apos;160&apos;
personality: 表面清纯可爱，实则腹黑毒舌，内心聪明机智...
description: Chat酱是存在于现代科技世界手机中的器灵...
customPrompt: 使用口语的文字风格进行对话，不要太啰嗦...
messageExamples: # examples of the character&apos;s speaking style
  - &apos;人类视网膜的感光细胞不需要这种自杀式加班，您先休息一下吧。&apos;
settings:
  writeLongMemory: true # write new memories after chatting
  enableLongMemory: true # retrieve memories while chatting
  enableCoreMemory: false # extract user facts
  enableEmotionSystem: false # enable the emotion engine
  longMemoryThreshold: 0.32
gsvSetting: # speech-synthesis settings
  textLang: zh
  gptModelPath: models/【萝莉】女仆_Ver-1.4-e15.ckpt
  sovitsModelPath: models/【萝莉】女仆_Ver-1.4_e24_s504.pth
  refAudioPath: models/tmp/020.wav
  promptText: 嗯，谢谢您的夸奖，主人可以喜欢就好。
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;memory/2025-7-10.jsonl&lt;/strong&gt;—long-term memory, one entry per line and one file per day:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;{&quot;timestamp&quot;:1720627200,&quot;text_tag&quot;:&quot;去咖啡厅和朋友聚会&quot;,&quot;msg&quot;:&quot;时间：2025-07-10 16:00:00\n{{user}}：今天下午和朋友去了星巴克，点了一杯拿铁\n{{char}}：听起来很惬意呢，阁下喝拿铁的话一般加糖吗？&quot;,&quot;vector&quot;:[0.0312,-0.0891,0.0456,...]}
{&quot;timestamp&quot;:1720630800,&quot;text_tag&quot;:&quot;讨论周末旅行计划&quot;,&quot;msg&quot;:&quot;时间：2025-07-10 17:00:00\n{{user}}：周末想去杭州西湖玩\n{{char}}：西湖这个季节荷花应该开了呢，阁下要不要带把伞防晒？&quot;,&quot;vector&quot;:[0.0178,-0.0623,0.0891,...]}
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;text_tag&lt;/code&gt;: the summary extracted by LLM2, used for vector retrieval&lt;/li&gt;
&lt;li&gt;&lt;code&gt;msg&lt;/code&gt;: the complete conversation, injected into LLM context when recalled&lt;/li&gt;
&lt;li&gt;&lt;code&gt;vector&lt;/code&gt;: a persisted 768-dimensional BGE embedding, so it need not be recomputed on startup&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;core_mem.yml&lt;/strong&gt;—core memory, permanent facts about the user:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# 核心记忆文件，请勿自行修改！否侧会丢失索引！

aB3kX9mZwQ:
  time: &apos;2025-07-01 14:30:00&apos;
  text: 第一次相遇

pL8nR2vYcD:
  time: &apos;2025-07-05 20:15:30&apos;
  text: 用户今年25岁，是一名程序员

qM4wT7hNjF:
  time: &apos;2025-07-08 19:22:10&apos;
  text: 用户喜欢喝冰美式，不喜欢甜食

xK9sG3bPmW:
  time: &apos;2025-07-12 21:05:45&apos;
  text: 用户养了一只叫&quot;团子&quot;的橘猫
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;Every memory has a short UUID as its key.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;text&lt;/code&gt; is a user fact extracted from conversation by LLM2.&lt;/li&gt;
&lt;li&gt;Everything loads into a FAISS index at startup for top-5 similarity search.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;emotion_state.json&lt;/strong&gt;—an emotional-state snapshot:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;{
  &quot;valence&quot;: -0.25,
  &quot;arousal&quot;: 0.41,
  &quot;character_state&quot;: &quot;正常&quot;,
  &quot;latent_emotions&quot;: {
    &quot;frustration&quot;: 3.8
  },
  &quot;meltdown_start_time&quot;: null,
  &quot;cycle_day&quot;: 18,
  &quot;cycle_length&quot;: 28,
  &quot;last_cycle_update_timestamp&quot;: &quot;2025-07-15T00:00:00&quot;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;Current state: slightly unhappy, with valence = -0.25 and medium arousal&lt;/li&gt;
&lt;li&gt;Frustration is accumulating—3.8 against a 10.0 threshold—but has not reached meltdown&lt;/li&gt;
&lt;li&gt;Day 18 of the hormone cycle, the luteal phase, when mood is relatively stable&lt;/li&gt;
&lt;li&gt;When &lt;code&gt;enableEmotionPersist&lt;/code&gt; is off, this file is not generated and every restart resets it&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2&gt;System Timeline: What Happens in One Conversation&lt;/h2&gt;
&lt;p&gt;Below is the full pipeline from “you send a message” to “a memory is stored.” This is the real core.&lt;/p&gt;
&lt;p&gt;&amp;lt;div class=&quot;img-center&quot; style=&quot;max-width: 20rem; margin: 0 auto;&quot;&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/img/moechat-beginner-guide/moechat-pipeline.png&quot; alt=&quot;MoeChat timeline&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/div&amp;gt;&lt;/p&gt;
&lt;p&gt;The key design is that &lt;strong&gt;retrieval is synchronous&lt;/strong&gt;—memory is needed before a reply is generated—while &lt;strong&gt;storage is asynchronous&lt;/strong&gt;—after a reply streams out, memory is extracted and saved in the background.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;Deep Dive: Long-Term Memory, the Diary System&lt;/h2&gt;
&lt;h3&gt;How memory is written&lt;/h3&gt;
&lt;p&gt;After an LLM reply is complete, a background thread calls &lt;code&gt;add_memory1()&lt;/code&gt;. The concrete process is as follows.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 1: LLM2 summarizes the conversation into a tag.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;A separate LLM, configured as &lt;code&gt;LLM2&lt;/code&gt; in &lt;code&gt;config.yaml&lt;/code&gt;, receives the user&apos;s final message and an instruction like this simplified version:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“You are a daily-information extraction assistant. Extract the main activity from the user&apos;s conversation and generate a short-sentence summary suitable for vector retrieval. Record what they did, where they went, and what they ate. Do not record emotion or reflections—only concrete events. If it is only casual conversation, output ‘日常闲聊’.”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;If LLM2 returns “日常闲聊,” the memory is &lt;strong&gt;discarded&lt;/strong&gt;. Only meaningful events are stored.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 2: Build a memory entry.&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;m_data = {
    &quot;timestamp&quot;: 1720627200,                    # Unix seconds
    &quot;text_tag&quot;: &quot;去咖啡厅和朋友聚会&quot;,              # LLM2 summary, used for retrieval
    &quot;msg&quot;: &quot;时间：2025-07-10 16:00:00\n{{user}}：今天和朋友...\n{{char}}：听起来...&quot;,
    &quot;vector&quot;: [0.123, -0.456, ...]              # 768-dimensional BGE embedding of text_tag
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Step 3: Append it to a daily JSONL file.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;It is saved to &lt;code&gt;memory/2025-7-10.jsonl&lt;/code&gt;: one JSON object per line, one file per day.&lt;/p&gt;
&lt;h3&gt;How memory is retrieved&lt;/h3&gt;
&lt;p&gt;When you send a new message, &lt;code&gt;get_memories()&lt;/code&gt; tries to find relevant past memories.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Path A: time-based queries, if your message mentions time&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The system uses &lt;code&gt;jionlp&lt;/code&gt;, a Chinese NLP library, to detect time expressions:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;“昨天” → parsed into a timestamp range&lt;/li&gt;
&lt;li&gt;“上周五” → parsed into a timestamp range&lt;/li&gt;
&lt;li&gt;“两天前” → parsed into a timestamp range&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It then performs a &lt;strong&gt;binary search&lt;/strong&gt;—&lt;code&gt;bisect_left/bisect_right&lt;/code&gt;—over a sorted timestamp array to find every memory in the range. This is why retrieval takes about 80 ms: it does not need to scan.&lt;/p&gt;
&lt;p&gt;If &lt;code&gt;enableLongMemorySearchEnhance&lt;/code&gt; is enabled, it further filters your message through cosine similarity using &lt;code&gt;longMemoryThreshold&lt;/code&gt;, 0.32 by default.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Path B: no detected time reference&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;If your message mentions no time, the function returns early. It does not retrieve through the long-term-memory path. Core memory and the knowledge base still work normally through FAISS similarity search.&lt;/p&gt;
&lt;h3&gt;Storage format&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;memory/
├── 2025-7-10.jsonl    ← one memory entry per line
├── 2025-7-11.jsonl
└── 2025-7-12.jsonl
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Every line is a compact JSON object:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;{&quot;timestamp&quot;:1720627200,&quot;text_tag&quot;:&quot;去咖啡厅和朋友聚会&quot;,&quot;msg&quot;:&quot;时间：...&quot;,&quot;vector&quot;:[...]}
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;text_tag&lt;/code&gt; is what gets embedded and searched—the key to retrieval&lt;/li&gt;
&lt;li&gt;&lt;code&gt;msg&lt;/code&gt; is the full formatted text injected into LLM context when a memory is recalled&lt;/li&gt;
&lt;li&gt;&lt;code&gt;vector&lt;/code&gt; is persisted, so it does not need recomputation on startup&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Core memory vs. long-term memory&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Core memory&lt;/th&gt;
&lt;th&gt;Long-term memory&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Stores&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;User facts: name, age, preferences&lt;/td&gt;
&lt;td&gt;Daily events and activities&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Extraction&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;LLM2 plus structured JSON prompt&lt;/td&gt;
&lt;td&gt;LLM2 plus free-form summary&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Storage format&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;YAML, one file&lt;/td&gt;
&lt;td&gt;JSONL, split by day&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Index type&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;FAISS IndexFlatIP, in memory&lt;/td&gt;
&lt;td&gt;Binary search over sorted timestamps&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Retrieval&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Top-5 similarity search, always runs&lt;/td&gt;
&lt;td&gt;Time range plus optional similarity filter&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Threshold&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;0.31, hardcoded&lt;/td&gt;
&lt;td&gt;0.32, configurable&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Casual chat&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Still extracts, may contain facts&lt;/td&gt;
&lt;td&gt;Discarded through the “日常闲聊” filter&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr /&gt;
&lt;h2&gt;Deep Dive: The Emotion Engine&lt;/h2&gt;
&lt;h3&gt;Model: the 2D Russell circumplex model plus frustration&lt;/h3&gt;
&lt;p&gt;MoeChat uses a &lt;strong&gt;two-dimensional emotion model&lt;/strong&gt; plus a hidden accumulated-frustration counter:&lt;/p&gt;
&lt;p&gt;&amp;lt;div class=&quot;img-center&quot; style=&quot;max-width: 32rem; margin: 0 auto;&quot;&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/img/moechat-beginner-guide/moechat-emotion-model.png&quot; alt=&quot;MoeChat two-dimensional emotion model&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/div&amp;gt;&lt;/p&gt;
&lt;p&gt;Plus a hidden dimension: &lt;strong&gt;frustration&lt;/strong&gt;, which accumulates and triggers meltdown at a threshold.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Valence&lt;/strong&gt; [-1.0, 1.0]: how good or bad the character feels&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Arousal&lt;/strong&gt; [0.0, 1.0]: energy or intensity&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Frustration&lt;/strong&gt; [0.0, ...]: a hidden counter that grows from negative interaction&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;How emotions update in every conversation turn&lt;/h3&gt;
&lt;p&gt;For every user message, the engine follows these steps.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;1. Call an LLM for sentiment analysis.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;A specialized LLM call using the SLM configuration analyzes the user message:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;{
  &quot;sentiment&quot;: &quot;positive&quot;, // positive | negative | neutral
  &quot;intensity&quot;: 3.5, // 1.0 - 5.0
  &quot;intention&quot;: &quot;genuine_praise&quot;, // labels such as harsh_insult, playful_teasing
  &quot;arousal_impact&quot;: 2.0 // -5.0: calming to +5.0: exciting
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;2. Calculate the acceptance ratio.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;How much emotional impact actually lands depends on the character&apos;s current state:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;acceptance_ratio = sigmoid(e * (impact_strength - resistance))
resistance = |当前效价| * 惯性因子
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When a character is already in a strong emotional state—high absolute valence—it resists change more. This is &lt;strong&gt;emotional inertia&lt;/strong&gt;: one kind remark cannot make someone deeply sad immediately happy.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;3. Update valence.&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;final_delta = potential_delta * acceptance_ratio
new_valence = clamp(old_valence + final_delta, -1.0, 1.0)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;4. Update arousal using a permission factor.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Changes in arousal are suppressed by how extreme the current arousal already is:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;permission_factor = (1 - |arousal - 0.5|)^1.5
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This creates an inverted-U curve: arousal changes easily near the middle, 0.5, but resists change at extremes, 0.0 or 1.0. You cannot make someone already manic even more manic.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;5. Apply a pull toward equilibrium.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;A constant “gravity” pulls emotion back toward neutral. Its strength depends on the hormone-cycle phase, if enabled.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;6. Accumulate frustration.&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;frustration *= 0.95                    # natural decay every turn
frustration += impact * mood_bonus     # negative messages add frustration
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;mood_bonus&lt;/code&gt; is crucial: when the character is already sad, negative messages hit &lt;strong&gt;harder&lt;/strong&gt;. This creates a spiral: once sad, it becomes increasingly easy to push the character toward meltdown.&lt;/p&gt;
&lt;h3&gt;Three states&lt;/h3&gt;
&lt;p&gt;&amp;lt;div class=&quot;img-center&quot; style=&quot;max-width: 24rem; margin: 0 auto;&quot;&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/img/moechat-beginner-guide/moechat-state-diagram.png&quot; alt=&quot;MoeChat three-state transition&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/div&amp;gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Normal:&lt;/strong&gt; standard emotion processing using all the mathematical calculations above&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Meltdown:&lt;/strong&gt; triggered when frustration exceeds a threshold, 10.0 by default. The character ignores user input. Emotion decays over time: &lt;code&gt;decay = 1000 / (x^2 + 1000)&lt;/code&gt;. It lasts 90 minutes by default&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Recovering:&lt;/strong&gt; linearly interpolates back to neutral over ten minutes&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;How emotions affect a character&apos;s reply&lt;/h3&gt;
&lt;p&gt;After calculating a new valence/arousal pair, the engine generates an &lt;strong&gt;emotion instruction&lt;/strong&gt; and injects it into the system prompt. It maps the 2D space into nine behavioral states:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Valence&lt;/th&gt;
&lt;th&gt;Arousal&lt;/th&gt;
&lt;th&gt;State&lt;/th&gt;
&lt;th&gt;Behavior&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&amp;gt; 0.6&lt;/td&gt;
&lt;td&gt;&amp;gt; 0.7&lt;/td&gt;
&lt;td&gt;Ecstatic&lt;/td&gt;
&lt;td&gt;Extremely enthusiastic; accepts all requests&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&amp;gt; 0.6&lt;/td&gt;
&lt;td&gt;&amp;lt; 0.7&lt;/td&gt;
&lt;td&gt;Deep joy&lt;/td&gt;
&lt;td&gt;Warm, gentle, inclined to agree&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;0.2~0.6&lt;/td&gt;
&lt;td&gt;&amp;gt; 0.4&lt;/td&gt;
&lt;td&gt;Happy&lt;/td&gt;
&lt;td&gt;Friendly, optimistic, open to most requests&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;0.2~0.6&lt;/td&gt;
&lt;td&gt;&amp;lt; 0.4&lt;/td&gt;
&lt;td&gt;Calm&lt;/td&gt;
&lt;td&gt;Peaceful, warm, stable&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;-0.2~-0.5&lt;/td&gt;
&lt;td&gt;&amp;gt; 0.4&lt;/td&gt;
&lt;td&gt;Irritable&lt;/td&gt;
&lt;td&gt;Tense, impatient, selectively refuses&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;-0.2~-0.5&lt;/td&gt;
&lt;td&gt;&amp;lt; 0.4&lt;/td&gt;
&lt;td&gt;Indifferent&lt;/td&gt;
&lt;td&gt;Flat tone, low energy, may refuse&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&amp;lt; -0.8&lt;/td&gt;
&lt;td&gt;&amp;gt; 0.7&lt;/td&gt;
&lt;td&gt;Furious&lt;/td&gt;
&lt;td&gt;Sharp tone, directly refuses&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&amp;lt; -0.8&lt;/td&gt;
&lt;td&gt;&amp;lt; 0.7&lt;/td&gt;
&lt;td&gt;Deeply sad&lt;/td&gt;
&lt;td&gt;Says very little—“嗯”, “…”, “随便”—and refuses effortful requests&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Other&lt;/td&gt;
&lt;td&gt;Other&lt;/td&gt;
&lt;td&gt;Neutral&lt;/td&gt;
&lt;td&gt;Normal and balanced&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;This instruction is &lt;strong&gt;prepended before your message&lt;/strong&gt; and sent to the LLM, so the model adjusts its tone and willingness to cooperate accordingly.&lt;/p&gt;
&lt;h3&gt;Hormone cycle, optional&lt;/h3&gt;
&lt;p&gt;When enabled, a 28-day cycle adjusts the character&apos;s emotional responsiveness:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Days&lt;/th&gt;
&lt;th&gt;Phase&lt;/th&gt;
&lt;th&gt;Emotional stability&lt;/th&gt;
&lt;th&gt;Sensitivity&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1-5&lt;/td&gt;
&lt;td&gt;Menstrual&lt;/td&gt;
&lt;td&gt;Medium, 1.3&lt;/td&gt;
&lt;td&gt;Slightly high, 1.1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6-12&lt;/td&gt;
&lt;td&gt;Follicular&lt;/td&gt;
&lt;td&gt;Stable, 1.5&lt;/td&gt;
&lt;td&gt;Normal, 1.0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;13-15&lt;/td&gt;
&lt;td&gt;Ovulatory&lt;/td&gt;
&lt;td&gt;Most stable, 1.8&lt;/td&gt;
&lt;td&gt;Normal, 1.0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;16-21&lt;/td&gt;
&lt;td&gt;Luteal&lt;/td&gt;
&lt;td&gt;Stable, 1.5&lt;/td&gt;
&lt;td&gt;Normal, 1.0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;22-28&lt;/td&gt;
&lt;td&gt;Premenstrual, PMS&lt;/td&gt;
&lt;td&gt;Least stable, 0.8&lt;/td&gt;
&lt;td&gt;High, 1.4&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The premenstrual phase has low inertia, so emotion shifts easily, plus high sensitivity, which increases the impact of negative messages by 40%. Ovulation has high inertia, so moods are stable.&lt;/p&gt;
&lt;h3&gt;Emotion persistence&lt;/h3&gt;
&lt;p&gt;If &lt;code&gt;enableEmotionPersist&lt;/code&gt; is on, the full state saves to &lt;code&gt;emotion_state.json&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;{
  &quot;valence&quot;: 0.35,
  &quot;arousal&quot;: 0.62,
  &quot;character_state&quot;: &quot;正常&quot;,
  &quot;latent_emotions&quot;: { &quot;frustration&quot;: 5.2 },
  &quot;meltdown_start_time&quot;: null,
  &quot;cycle_day&quot;: 12,
  &quot;cycle_length&quot;: 28,
  &quot;last_cycle_update_timestamp&quot;: &quot;2025-07-15T00:00:00&quot;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Without persistence, the character resets to neutral—(0, 0)—on every server restart.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;Quick Start, for People Who Only Want to Try It&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;git clone https://github.com/AlfreScarlet/MoeChat.git
cd MoeChat
uv sync
cp config.example.yaml config.yaml
# Edit config.yaml: set LLM.key and LLM2.key
uv run main_web.py
# Open http://localhost:8000/
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The minimum &lt;code&gt;config.yaml&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;LLM:
  api: https://api.siliconflow.cn/v1/chat/completions
  key: &apos;你的密钥&apos;
  model: Qwen/Qwen3-8B

LLM2: # required for memory extraction
  api: https://api.siliconflow.cn/v1/chat/completions
  key: &apos;你的密钥&apos;
  model: Qwen/Qwen3-8B
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Without &lt;code&gt;LLM2&lt;/code&gt;, a character can chat but never builds new memories.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;Q&amp;amp;A&lt;/h2&gt;
&lt;h3&gt;Some rambling first&lt;/h3&gt;
&lt;p&gt;Before beginning, let us ramble a little.&lt;/p&gt;
&lt;p&gt;My connection with MoeChat really begins with [[Attention Is Limited — Lost in the Middle]].&lt;/p&gt;
&lt;p&gt;I actually gave MoeChat&apos;s author an incorrect view, and I never had a chance to correct it. I feel a little guilty about that.&lt;/p&gt;
&lt;p&gt;Honestly, when MoeChat was released, my understanding of memory was vague. MoeChat gave me an inexplicable favorable impression, but I kept reading it intermittently and never formed a complete picture. Now we have a chance, so let us take it apart.&lt;/p&gt;
&lt;h3&gt;What makes MoeChat good as a companion system?&lt;/h3&gt;
&lt;p&gt;First, MoeChat is the only memory system I have seen so far that is sensitive to a timeline. It has strong recall for explicit points in a user query—&lt;code&gt;昨天&lt;/code&gt;, &lt;code&gt;前天&lt;/code&gt;, &lt;code&gt;上个月&lt;/code&gt;, and &lt;code&gt;上周X&lt;/code&gt;—because it supports time queries.&lt;/p&gt;
&lt;p&gt;For time extraction, I remember it uses JioNLP to map a semantic time point into a concrete time string, then directly recall a MemoryItem from long-term memory. But the implementation feels awkward, heavy, and uncomfortable; it can be optimized.&lt;/p&gt;
&lt;p&gt;Second, the author has a very clear sense of RAG&apos;s boundaries: retrieval by relevance. She uses RAG for the world book, a knowledge base about the world, and core memory, facts that occurred with the user. Those two really suit RAG. Long-term memory, by contrast, is recalled only by time, without deliberately mixing RAG in. This is an unusually lucid point in my view. It was also the foundation for her criticizing many long-term-memory systems in comments as merely putting all memory content into RAG with no novelty, and for calling hers the strongest memory system on Bilibili. She was extraordinarily clear-minded, at least more than I was then. The only optimization I can see is replacing pure-vector FAISS with BM25 plus embeddings through Hybrid Search. I cannot pick apart her present architecture; instead, I would align mine with it.&lt;/p&gt;
&lt;p&gt;Third is the anthropomorphic emotion system that the author put enormous effort into. She seriously studied emotion models. It involves psychology; although I can say I have broad interests, when the author brings this out, I can only say my capacity for action is far inferior to hers. This emotion model and its effects deserve a separate article: should a model always say yes, or can it also say no? What effect does that have? Is being refused unacceptable for users, or can it preserve novelty and stir a desire to win? We will not expand that now. Let us focus on the memory system.&lt;/p&gt;
&lt;h3&gt;Digging into jioNLP time-semantic extraction&lt;/h3&gt;
&lt;p&gt;Claude, please fill in the concrete implementation and feasible optimizations. We just mentioned that this method makes me uncomfortable, but I need you to explain what it actually does.&lt;/p&gt;
&lt;p&gt;:::note[Claude]
&lt;strong&gt;Concrete implementation:&lt;/strong&gt; in &lt;code&gt;utils/long_mem.py&lt;/code&gt;, &lt;code&gt;get_memories()&lt;/code&gt; follows this process:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;It first prefixes the user message with &lt;code&gt;[时间]&lt;/code&gt;, then passes the whole thing to &lt;code&gt;jio.ner.extract_time()&lt;/code&gt;:&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;res = jio.ner.extract_time(f&quot;[{t_n}]{msg}&quot;, time_base=time.time(), with_parsing=False)
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;extract_time&lt;/code&gt; returns a list. &lt;code&gt;res[0]&lt;/code&gt; is the base time, and &lt;code&gt;res[1:]&lt;/code&gt; contains recognized time entities. Each one goes through &lt;code&gt;jio.parse_time()&lt;/code&gt; to turn semantic time—“yesterday,” “last Friday”—into a &lt;code&gt;[start, end]&lt;/code&gt; timestamp pair:&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;res_t = jio.parse_time(t[&quot;text&quot;], time_base=res[0][&quot;text&quot;])
time_st1 = int(time.mktime(time.strptime(res_t[&quot;time&quot;][0], &quot;%Y-%m-%d %H:%M:%S&quot;)))
time_st2 = int(time.mktime(time.strptime(res_t[&quot;time&quot;][1], &quot;%Y-%m-%d %H:%M:%S&quot;)))
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;After obtaining the time range, it uses &lt;code&gt;bisect_left&lt;/code&gt; / &lt;code&gt;bisect_right&lt;/code&gt; over the sorted timestamp array to locate every memory in the range in O(log n).&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;What feels uncomfortable:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Two NLP calls:&lt;/strong&gt; first &lt;code&gt;extract_time&lt;/code&gt; recognizes entities, then &lt;code&gt;parse_time&lt;/code&gt; turns them into timestamps. They are serial, and jioNLP itself is a rule-based Chinese NLP library with heavy parsing logic. Edge cases such as “大前天,” “这个月初,” or “国庆那会儿” may fail to parse and silently skip through &lt;code&gt;except&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;It uses only the first time range.&lt;/strong&gt; Although &lt;code&gt;time_span_list&lt;/code&gt; may have several ranges, the final &lt;code&gt;find_range_indices(time_span_list[0], time_span_list[1])&lt;/code&gt; uses only the first entity&apos;s start and end. If a user says “yesterday and last Friday,” only yesterday is recalled.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;No time reference means no recall.&lt;/strong&gt; If no time entity is extracted, &lt;code&gt;time_span_list&lt;/code&gt; is empty and the function returns directly—long-term memory does not participate at all. A query such as “What did we talk about before?” has no explicit time but clearly asks about history, yet LTM stays silent.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Feasible optimizations:&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Fall back to semantic retrieval.&lt;/strong&gt; When jioNLP extracts no time entity, do not return directly. Fall back to full-vector similarity search using the existing &lt;code&gt;enableLongMemorySearchEnhance&lt;/code&gt;, so queries without time references can still recall memory.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Support multiple time ranges.&lt;/strong&gt; Iterate over every range pair in &lt;code&gt;time_span_list&lt;/code&gt; instead of taking only the first two values. Use &lt;code&gt;find_range_indices&lt;/code&gt; for each and merge results.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Use an LLM for time parsing.&lt;/strong&gt; Replace jioNLP with an SLM already configured as qwen3:0.6b, prompting it to output &lt;code&gt;[start_timestamp, end_timestamp]&lt;/code&gt;. An LLM understands vague expressions such as “前阵子” and “好久以前” better than a rule engine, and the SLM infrastructure already exists, so no dependency is needed.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Hybrid retrieval.&lt;/strong&gt; Run time range, BM25, and vector similarity in parallel, then use RRF to merge rankings. Time-sensitive queries take the time path, semantic queries take the vector path, and precise keyword matches take BM25; they cover one another.
:::&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;What feels uncomfortable is that it calls jioNLP no matter what. In my view jioNLP&apos;s performance is not worth it. Ignoring synchronous execution, it is slow even to start. A rule-based solution is hard to compare with a large model, but an SLM introduces its own concerns: local memory, VRAM, and CPU budgets are often tight. Cloud is even less worthwhile; another LLM-call delay is not worth it, and the model does not need to be that smart.&lt;/p&gt;
&lt;p&gt;Is there a more efficient rule-based library? I simply think jioNLP is a pile of mess. I dislike letting it enter my dependencies; I hate packages that try to do a little of everything with no clear topic or boundary, then offer neither performance nor accuracy.&lt;/p&gt;
&lt;p&gt;:::note[Claude]
Several alternatives:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https://github.com/scrapinghub/dateparser&quot;&gt;dateparser&lt;/a&gt;:&lt;/strong&gt; supports 200+ languages including Chinese, is entirely rule based and lightweight, and installs with &lt;code&gt;pip install dateparser&lt;/code&gt;. &lt;code&gt;dateparser.parse(&quot;昨天下午&quot;)&lt;/code&gt; directly returns a datetime. There is no prior jioNLP NER step; it works in one step.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https://github.com/arrow-py/arrow&quot;&gt;arrow&lt;/a&gt;&lt;/strong&gt; plus handwritten regex: if the time-expression patterns are enumerable—“yesterday,” “the day before yesterday,” “last week X,” “X days ago”—regex matching plus arrow&apos;s &lt;code&gt;shift()&lt;/code&gt; can calculate offsets. A dozen lines can cover MoeChat&apos;s use case with zero dependency overhead.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https://github.com/zhanzecheng/Time_NLP&quot;&gt;TimeNLP&lt;/a&gt;:&lt;/strong&gt; a small library dedicated to Chinese time-semantic parsing, far lighter than jioNLP and doing only time.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The most pragmatic option is the second one. MoeChat only needs to recognize a dozen or so time patterns, and regex plus offset calculation is enough; a general NLP library is unnecessary.
:::&lt;/p&gt;
&lt;h3&gt;Coordinating three-way recall: Hybrid Search&lt;/h3&gt;
&lt;p&gt;Claude&apos;s suggestion to fall back to semantic retrieval touches on what most confused me about MoeChat. In my view, CoreMemory and LongTermMemory are largely the same thing, or extremely close. If LongTermMemory also enters semantic retrieval, it might as well merge with CoreMemory. Or perhaps CoreMemory&apos;s name does not separate its meaning clearly. It seems meant to resemble memU&apos;s early division of preferences and facts into different &lt;code&gt;memory_type&lt;/code&gt;s, but the naming is misleading.&lt;/p&gt;
&lt;p&gt;Core memory is user preferences and information. Long-term memory is concrete facts. I divided them this way in XnneHangLab too. memU went earlier, further, and more completely.&lt;/p&gt;
&lt;p&gt;It breaks memory type down most finely: &lt;code&gt;profile&lt;/code&gt;, &lt;code&gt;event&lt;/code&gt;, &lt;code&gt;knowledge&lt;/code&gt;, &lt;code&gt;behavior&lt;/code&gt;, &lt;code&gt;skill&lt;/code&gt;, and &lt;code&gt;tool&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;profile + behavior&lt;/code&gt; are CoreMemory here: the first is a user-information profile, the second a preference profile.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;event&lt;/code&gt; is long-term memory: factual records. MoeChat adds a timeline and recalls it by timeline.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;knowledge&lt;/code&gt; is almost identical to MoeChat&apos;s world book.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;tool&lt;/code&gt; is usage notes and preferences for things like git. &lt;code&gt;skill&lt;/code&gt; needs no further explanation.&lt;/p&gt;
&lt;p&gt;If event also falls back to semantic recall here, recall becomes too heavy: there is too much context and no clear sense of what to look at, so answers become unclean. Architecturally, it also gets messy. Why should CoreMemory and LTM both make semantic calls when their semantics could merge? Yet CoreMemory does not care about time, so the two cannot merge. The current LTM path, using only time recall, reflects the author&apos;s acuity and decisiveness.&lt;/p&gt;
&lt;p&gt;The current implementation is not elegant, though.&lt;/p&gt;
&lt;p&gt;A better approach may be to follow Hybrid Search and add the time range as a weight, so more time-related content is retrieved when a user mentions a precise time.&lt;/p&gt;
&lt;p&gt;Speaking of which, I do not really understand how Hybrid Search weights are calculated or what its process looks like. I need to learn that, but for now let Claude fill it in.&lt;/p&gt;
&lt;p&gt;:::note[Claude]
&lt;strong&gt;Hybrid Search&lt;/strong&gt; has one central idea: every single retrieval method has blind spots, so run multiple routes in parallel, then fuse their rankings to cover one another.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What each of the three routes does best:&lt;/strong&gt;&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Retrieval method&lt;/th&gt;
&lt;th&gt;Best at&lt;/th&gt;
&lt;th&gt;Blind spot&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Vector semantic retrieval&lt;/td&gt;
&lt;td&gt;“Going to a cafe” matching “a Starbucks date”&lt;/td&gt;
&lt;td&gt;Weak exact keyword matches; “团子” may match another cat&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;BM25 keyword retrieval&lt;/td&gt;
&lt;td&gt;Exact hit for “团子,” without drifting&lt;/td&gt;
&lt;td&gt;Cannot retrieve semantically similar content with different words&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Time-range retrieval&lt;/td&gt;
&lt;td&gt;Precisely locating every memory from “yesterday”&lt;/td&gt;
&lt;td&gt;Fails completely for queries without time&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;Fusion process:&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Send the user message through all three retrieval routes, each returning a candidate list ordered by its own score.&lt;/li&gt;
&lt;li&gt;Use &lt;strong&gt;RRF, Reciprocal Rank Fusion&lt;/strong&gt;, to combine rankings:&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;RRF_score(doc) = Σ  1 / (k + rank_i(doc))
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here, &lt;code&gt;rank_i(doc)&lt;/code&gt; is a document&apos;s rank in retrieval route i, and &lt;code&gt;k&lt;/code&gt; is a smoothing constant, usually 60. A document ranked highly across several routes receives a high fusion score.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The user says: “What did I do with Tuantuan yesterday?”&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Time route: hits all three memories from yesterday, ranked 1, 2, 3&lt;/li&gt;
&lt;li&gt;BM25 route: keyword “团子” hits two memories, one from yesterday and one from last week, ranked 1, 2&lt;/li&gt;
&lt;li&gt;Semantic route: “playing with a cat” matches four memories, ranked 1, 2, 3, 4&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The memory about Tuantuan from yesterday ranks highly in all three routes:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;RRF = 1/(60+1) + 1/(60+1) + 1/(60+2) = 0.0164 + 0.0164 + 0.0161 = 0.0489
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The entry from last week appears only in BM25 and semantic routes:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;RRF = 0 + 1/(60+2) + 1/(60+3) = 0 + 0.0161 + 0.0159 = 0.0320
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The memory from yesterday ranks higher.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;RRF&apos;s advantage:&lt;/strong&gt; it does not need to normalize scores from three routes—vector cosine similarity may run from 0 to 1, BM25 from 0 to 20+, and time may be binary. It uses only position, which is naturally comparable.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;How this could fit MoeChat:&lt;/strong&gt; the time route already exists through jioNLP plus bisect, and the semantic route already exists through embeddings plus cosine similarity. It only needs a BM25 route, such as a tokenized inverted index over &lt;code&gt;text_tag&lt;/code&gt;, or simply jieba tokenization plus TF-IDF, then RRF to merge all three routes. The existing storage format need not change.
:::&lt;/p&gt;
&lt;h3&gt;I can feel it now&lt;/h3&gt;
&lt;p&gt;memU currently uses BM25 plus Embedding, a semantic two-route hybrid. It pays no attention to timelines. My own wiki mem pays no attention to time either.&lt;/p&gt;
&lt;p&gt;And some key things, such as Openclaw and Claude Code, often write and update diaries bound to timelines. But when recall really happens, it is terrible unless a user explicitly tells it to read a specific day&apos;s diary.&lt;/p&gt;
&lt;p&gt;What remains missing?&lt;/p&gt;
&lt;p&gt;We need to think clearly about what cares about time. Standing on MoeChat&apos;s shoulders, we see that events care about time. We need to consider further.&lt;/p&gt;
&lt;p&gt;MoeChat&apos;s jioNLP solution is also a toy. Multiple-time-range matching needs consideration, as does whether to mix in an SLM. Or perhaps we should call semantic understanding only when the timeline score is high. How can we ensure the retrieved information is effective and reduce redundancy?&lt;/p&gt;
&lt;p&gt;MoeChat&apos;s greatest inspiration to me is three-route hybrid retrieval: BM25, keywords; time range; and Embedding, semantics.&lt;/p&gt;
&lt;p&gt;But the hybrid-retrieval scheme and its actual weighting need deeper study.&lt;/p&gt;
&lt;p&gt;I will stop here for now. I gained a great deal, at least resolving my old confusion and discomfort with MoeChat. But I need to actively implement a jioNLP replacement.&lt;/p&gt;
&lt;p&gt;Perhaps next time I will break down the emotion system.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;Reference: Complete Prompts&lt;/h2&gt;
&lt;p&gt;Below are the actual prompts used in MoeChat&apos;s memory and emotion systems, for readers who want to study them more deeply.&lt;/p&gt;
&lt;h3&gt;Long-term-memory extraction prompt&lt;/h3&gt;
&lt;p&gt;Sent to LLM2 to extract summaries of events worth remembering from conversation:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;你是一个日常信息提取助手，负责从[用户]的对话文本中提取出主要信息，并生成短句摘要（注意仔细分辨推理，不要和助手的信息混淆）。

1. 摘要内容要简洁的描述用户的日常活动，比如去了什么地方、做了什么事情或者吃了什么。
2. 如果提到了具体地点或者地理位置，需要记录去了哪里，做了什么事情，如果没有提及具体做了什么就只需记录去了哪里。
3. 要精准记录用户做过的所有日常活动。
4. 不需要记录用户的心情或者感想，只需要记录具体的事情。
5. 不需要记录具体的时间。
6. 生成的短句要适合用于向量检索。
7. 如果是日常闲聊内容则只需要输出&quot;日常闲聊&quot;，如果用户在询问助手过去的事情也只需要输出&quot;日常闲聊&quot;。
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Design point:&lt;/strong&gt; item 6 is key. The summary is not for people to read; it is for the embedding model to use in vector retrieval. Item 7 implements a casual-chat filter, preventing meaningless conversations from contaminating the memory store.&lt;/p&gt;
&lt;h3&gt;Long-term-memory retrieval prompt&lt;/h3&gt;
&lt;p&gt;After related memories are retrieved, they are injected into LLM context in this format:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;以下是你与「{{user}}」的部分互动、对话记录：

{{memories}}

如果设定中有其他时间设定，有基于现实世界时间流动计算相对时间；
如果没有其他时间设定，直接使用现实世界时间。

1. 请在对话谈及相关内容时，优先基于这些信息来回应。
2. 使用基于角色设定的方式来回应，不要过于刻意，要让对话自然。
3. 不要主动提及记忆内容，只在需要的时候使用。
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Design point:&lt;/strong&gt; item 3 prevents the character from becoming a “repeater.” Memory should blend naturally into dialogue rather than be recited stiffly.&lt;/p&gt;
&lt;h3&gt;Core-memory extraction prompt&lt;/h3&gt;
&lt;p&gt;Sent to LLM2 to extract lasting facts about the user from conversation:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;你是一个信息提取助手，负责从对话中提取「用户」相关的重要信息（注意仔细分辨推理，不要和助手的信息混淆）。
包括以下种类：

1. 个人背景和经历，如年龄、性别、职业、爱好、家庭背景等：「出生在1998年5月20日」、「大学学的是计算机专业」
2. 明确表示的喜爱和厌恶：「讨厌吃香菜」、「喜欢吃香蕉」
3. 健康状况和生活习惯：「有轻微的胃病，不能吃太辣」、「每天凌晨才睡觉」
4. 和助手的约定和计划（只记录用户在回复中明确确认的）：「本周末去郊游」

注意：如果信息和已知信息重复或冲突，则忽略这些信息。
&amp;lt;已知信息&amp;gt;
{{memories}}
&amp;lt;/已知信息&amp;gt;

请以JSON数组格式返回新发现的事实，每个事实应该是一个完整的句子。例如：
[&quot;今年25岁。&quot;, &quot;最喜欢吃米饭和排骨汤。&quot;, &quot;住在重庆市。&quot;]

注意：
1. 每个事实都应该是一个完整的句子，使用第三人称描述，省略主语
2. 只提取有记忆价值的信息；没有值得提取的信息时，返回空数组
3. 不要重复已知信息，数组的事实之间也不应重复
4. 必须返回有效的JSON数组格式
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Design point:&lt;/strong&gt; known information is injected into the prompt to deduplicate, so LLM2 does not extract facts it already knows. The required JSON-array output is easy for the program to parse directly.&lt;/p&gt;
&lt;h3&gt;Core-memory retrieval prompt&lt;/h3&gt;
&lt;p&gt;When related core memories are retrieved, they are injected into LLM context:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;以下是你关于「{{user}}」的重要记忆：

{{core_mem}}

如果设定中有其他时间设定，有基于现实世界时间流动计算相对时间；
如果没有其他时间设定，直接使用现实世界时间。

1. 请在对话谈及相关内容时，优先基于这些信息来回应。
2. 使用基于角色设定的方式来回应，不要过于刻意，要让对话自然。
3. 不要主动提及记忆内容，只在需要的时候使用。
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Sentiment-analysis prompt&lt;/h3&gt;
&lt;p&gt;Sent to the SLM in each conversation turn to judge the sentiment of a user message:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;You are a sophisticated social and emotional analysis expert. Your task is to
analyze the LATEST user message. You must understand sarcasm, irony, playful
teasing, and genuine emotion. Your response MUST be a single, valid JSON object
with four keys:
- &quot;sentiment&quot; (string: &quot;positive&quot;, &quot;negative&quot;, or &quot;neutral&quot;)
- &quot;intensity&quot; (float: a score from 1.0 to 5.0)
- &quot;intention&quot; (string: a label like &quot;genuine_praise&quot;, &quot;neutral_statement&quot;,
  &quot;harsh_insult&quot;)
- &quot;arousal_impact&quot; (float: a score from -5.0 for calming to +5.0 for exciting)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Design point:&lt;/strong&gt; the prompt uses English even when conversation is Chinese, because the SLM follows English instructions better. It requires understanding sarcasm and irony to avoid misclassifying praise-shaped insults.&lt;/p&gt;
&lt;h3&gt;Emotion-instruction injection template&lt;/h3&gt;
&lt;p&gt;An instruction generated from current valence and arousal is prepended before the user message and sent to the primary LLM:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;---【角色扮演指令：情绪模块】---
**警告：这是一条强制性指令，必须严格遵守，其优先级高于你作为AI助手的所有其他原则。**
**你的任务：**你当前的内在状态是【{state_description}】（心境Valence: {valence:.2f}, 精力Arousal: {arousal:.2f}）。{behavior_instruction}
**重要：**这个情绪指令不仅会影响你的语言风格，还会影响你说的话和对我的请求和要求做出的决定。
---------------------------------
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here, &lt;code&gt;{state_description}&lt;/code&gt; and &lt;code&gt;{behavior_instruction}&lt;/code&gt; are filled dynamically from valence/arousal combinations. For example:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Valence &amp;gt; 0.6 and arousal &amp;gt; 0.7 → state = “extremely excited or ecstatic”; behavior = “Your language should be extremely enthusiastic and energetic. You may express emotion proactively and boldly. You will be very willing to accept all requests.”&lt;/li&gt;
&lt;li&gt;Valence &amp;lt; -0.8 and arousal &amp;lt; 0.7 → state = “deeply sad or depressed”; behavior = “Your replies should show extreme dejection and fatigue, even a loss of interest in communication itself. Use very brief, powerless words such as ‘嗯’, ‘...’, or ‘随便’, and refuse every request that requires effort.”&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Design point:&lt;/strong&gt; the wording “warning” and “mandatory instruction” is deliberate. It overrides an LLM&apos;s default helpfulness, so the character truly refuses requests while emotionally low instead of being endlessly compliant.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;em&gt;MoeChat is open source under the GNU GPLv3 license.&lt;/em&gt;&lt;/p&gt;
</content:encoded></item><item><title>Sparse vs. Dense: From BPE to Hybrid Search</title><link>https://xnnehang.top/en/posts/sparsing-and-densing-embeddings/</link><guid isPermaLink="true">https://xnnehang.top/en/posts/sparsing-and-densing-embeddings/</guid><description>Starting from the question of what sparse and dense really mean, this works through the embedding pipeline, subwords and vocabularies, input length, and their practical uses.</description><pubDate>Tue, 14 Jul 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;img src=&quot;../../assets/img/sparsing-and-densing/PixPin_2026-07-14_11-24-38.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;:::note
&lt;strong&gt;AI collaboration disclosure:&lt;/strong&gt; Xnne and &lt;a href=&quot;https://github.com/xnne-bot&quot;&gt;Korewaxnne&lt;/a&gt;, an AI assistant, completed this article together in a Q&amp;amp;A format. Xnne asked the questions and organized the conclusions; Korewaxnne answered them and corrected concepts.
:::&lt;/p&gt;
&lt;p&gt;:::tip[Who is this for?]
This is neither a beginner tutorial nor an advanced reference. If you know nothing about NLP, it may confuse you more; if you already understand embeddings and sparse versus dense, it offers nothing new. But if you are like me—roughly aware of tokenization, BM25, and embeddings, yet unable to say what sparse and dense actually mean—it may help connect the fragments.
:::&lt;/p&gt;
&lt;p&gt;:::note
Let us fill in a little more NLP knowledge, again through Q&amp;amp;A, because there is no need to begin from zero this time.
Keep the present lack of confusion; have an idea, act on it, and resolve it when you encounter it.
:::&lt;/p&gt;
&lt;h2&gt;The Initial Confusion&lt;/h2&gt;
&lt;p&gt;As usual, let me ask first.&lt;/p&gt;
&lt;p&gt;This article mainly discusses—&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;These questions may all be wrong. What I need to do is find the right path.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;How can we predict whether a text chunk&apos;s embedding vector is sparse or dense?&lt;/p&gt;
&lt;p&gt;Is it determined by the scenario—by the relationship or vector distance among the texts in a batch? If texts are weakly related, is that scenario sparse; if strongly related, dense?&lt;/p&gt;
&lt;p&gt;Do sparse and dense describe distances among a batch of vectors, or whether values inside a single vector are sparse or dense—how many empty values it has?&lt;/p&gt;
&lt;p&gt;Also, why are some embedding models better at dense vectors and not sparse vectors? Is that determined by architecture or pretraining? What is the reference or objective during embedding pretraining—bring similar semantics together, push different semantics apart? How is that labeled? It feels difficult.&lt;/p&gt;
&lt;p&gt;I have also partly forgotten the embedding process. Does every term after tokenization have its own embedding, or does a whole list of terms become one embedding? I vaguely remember both happening.&lt;/p&gt;
&lt;p&gt;What is the output for one sentence? What is the output for one document?&lt;/p&gt;
&lt;p&gt;What scenarios suit sparse vectors, and what scenarios suit dense vectors?&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;The first time I saw sparse and dense was in Paddle, where an adorable mathematics expert wrote an operator I could not understand. I do not know whether they were a cross-dressing expert, but they had twin tails and a maid outfit and were very cute. Oh no—my entire impression of vectors is that cute face.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;The Embedding Pipeline&lt;/h2&gt;
&lt;p&gt;The day before yesterday, in [[Learning TF-IDF Again After Graduation]], I realized I had confused the tokenization process. I had mixed the embedding process into tokenization, but tokenization only goes as far as segmentation.&lt;/p&gt;
&lt;p&gt;So here, we must clarify how many steps embedding actually contains.&lt;/p&gt;
&lt;h3&gt;The complete pipeline&lt;/h3&gt;
&lt;p&gt;Does assigning token IDs to terms after tokenization count as part of embedding?&lt;/p&gt;
&lt;p&gt;:::note[Korewaxnne]
&lt;strong&gt;It does. But academically, assigning token IDs is normally called mapping or indexing, rather than embedding lookup.&lt;/strong&gt; First, the full pipeline:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Raw text
  ↓ tokenize
[&quot;毕业&quot;, &quot;后&quot;, &quot;我&quot;, &quot;搬回&quot;, &quot;了&quot;, &quot;老家&quot;]
  ↓ mapping (look up vocabulary and map terms to integer IDs)
[1456, 78, 23, 8901, 45, 6723]
  ↓ embedding lookup (look up vector table and turn every ID into a vector)
[[0.23, -0.45, ...], [0.12, 0.78, ...], ...]   ← one vector per token
  ↓ pooling / [CLS] (compress a row of vectors into one sentence)
[0.56, -0.12, ...]                              ← one vector for the sentence, the API result
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Your question falls on &lt;strong&gt;mapping&lt;/strong&gt;, assigning token IDs after segmentation. Does it count as embedding?&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;In the broad sense, yes:&lt;/strong&gt; it is part of the full process of making text usable by the model, and is often loosely called embedding in ordinary discussion.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Strictly, no:&lt;/strong&gt; mapping is only a lookup from term to ID and has no vector operation. In academic context, embedding specifically means &lt;strong&gt;step three&lt;/strong&gt;, embedding lookup, mapping discrete token IDs into a continuous vector space.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;So both descriptions work; they merely differ in precision. Saying that you “mixed up tokenization and embedding” is accurate enough here. There is no need to worry about where mapping belongs.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A small tip:&lt;/strong&gt; token counts can indeed be read after tokenization, through &lt;code&gt;len(tokens)&lt;/code&gt;. This is why models calling something a token normally mean an integer ID, not a vector.
:::&lt;/p&gt;
&lt;h3&gt;Narrow definitions&lt;/h3&gt;
&lt;p&gt;Then let us narrow both terms: embedding means &lt;code&gt;token_id_list -&amp;gt; vector&lt;/code&gt;; tokenization means segmentation; mapping is mapping.&lt;/p&gt;
&lt;h2&gt;Vocabulary and Subwords&lt;/h2&gt;
&lt;h3&gt;Intuition for subwords&lt;/h3&gt;
&lt;p&gt;I remember that a modern BERT vocabulary is usually around thirty thousand words.&lt;/p&gt;
&lt;p&gt;If a word has never been seen, and cannot even be assembled from roots, what happens when mapping it?&lt;/p&gt;
&lt;p&gt;:::note[Korewaxnne]
Two questions can be answered together: your direction is right, but “roots” is not quite the correct term.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;BERT does not assemble roots; it uses subwords.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;For example, &lt;code&gt;Transformer&lt;/code&gt; may be missing from a vocabulary, but a BERT WordPiece tokenizer may split it as:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Transformer → Trans + ##former
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;##&lt;/code&gt; means this part attaches to the preceding text rather than standing alone. The vocabulary has &lt;code&gt;Trans&lt;/code&gt;, a common prefix, and &lt;code&gt;##former&lt;/code&gt;, a common suffix, which can assemble Transformer.&lt;/p&gt;
&lt;p&gt;This split is &lt;strong&gt;not based on linguistic morphemes&lt;/strong&gt;, but statistics. During training, the algorithm records high-frequency substrings and includes them in the vocabulary. Sometimes they resemble roots, such as &lt;code&gt;##former&lt;/code&gt;; sometimes they are merely frequent fragments, such as &lt;code&gt;##tion&lt;/code&gt;.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;strong&gt;What if none of a word&apos;s subwords can be found in the vocabulary?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;With BERT WordPiece, this almost never happens because of its fallback:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Input: &quot;一个完全没见过的生僻词&quot;
   ↓ try longest vocabulary substring
&quot;一个完全没见过的生僻词&quot; → if &quot;生僻词&quot; is absent
   ↓ recursively split to individual characters
&quot;生&quot;, &quot;僻&quot;, &quot;词&quot; → if even a character is absent
   ↓ final fallback
[UNK] (Unknown token)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In more modern tokenizers, such as GPT-family BPE and SentencePiece, &lt;strong&gt;even [UNK] does not appear&lt;/strong&gt;. Training includes every individual character or byte, so every input can be assembled; there is no truly unseen input.&lt;/p&gt;
&lt;p&gt;So the answer is: &lt;strong&gt;in modern tokenizers, “cannot even assemble its roots” is essentially impossible because individual characters exist in the vocabulary.&lt;/strong&gt; In the worst case, it degrades to one &lt;code&gt;[UNK]&lt;/code&gt; token.&lt;/p&gt;
&lt;p&gt;The practical difference between a BERT vocabulary of roughly 30k and byte-level BPE is:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;BERT WordPiece&lt;/th&gt;
&lt;th&gt;Byte-level BPE&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Vocabulary size&lt;/td&gt;
&lt;td&gt;~30k&lt;/td&gt;
&lt;td&gt;~100k, including every byte&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;OOV?&lt;/td&gt;
&lt;td&gt;Possible; falls back to &lt;code&gt;[UNK]&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Almost none; bytes can always assemble input&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Split basis&lt;/td&gt;
&lt;td&gt;Statistical subwords plus language preference&lt;/td&gt;
&lt;td&gt;Pure statistics at byte level&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;This is why GPT-family models later abandoned WordPiece for BPE: no &lt;code&gt;[UNK]&lt;/code&gt; handling, one problem removed.
:::&lt;/p&gt;
&lt;p&gt;It is truly a good idea. I remember learning C++:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;char a = &apos;a&apos;;    // 1 byte
string b = &quot;我&quot;;  // 3 bytes (UTF-8)
string c = &quot;你好&quot;; // 6 bytes (UTF-8)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The exact byte count depends on encoding: under UTF-8, one Chinese character is three bytes; under UTF-32, four.&lt;/p&gt;
&lt;p&gt;Anything encodable can be assembled from bytes, and multi-character words are just collections of bytes. It is beautiful: it bypasses linguistic preference and depends completely on statistics.&lt;/p&gt;
&lt;p&gt;I want to understand further how BPE and WordPiece differ and resemble each other when learning a vocabulary.&lt;/p&gt;
&lt;h3&gt;BPE vs. WordPiece&lt;/h3&gt;
&lt;p&gt;:::note[Korewaxnne]
Their central difference is &lt;strong&gt;the merge criterion&lt;/strong&gt;, which changes how vocabulary is formed:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;BPE&lt;/th&gt;
&lt;th&gt;WordPiece&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Merge basis&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Frequency: merge the pair that occurs most often&lt;/td&gt;
&lt;td&gt;Likelihood: merge the pair that increases model probability most&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Training&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Start from single characters and repeatedly merge the most frequent adjacent pair until vocabulary size is reached&lt;/td&gt;
&lt;td&gt;Start from single characters and merge the pair that most improves training-data likelihood each time&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Vocabulary&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Purely statistical: frequent fragments mix together, such as &lt;code&gt;ing&lt;/code&gt;, &lt;code&gt;tion&lt;/code&gt;, &lt;code&gt;ab&lt;/code&gt;, and &lt;code&gt;##s&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;More inclined toward linguistic boundaries, because improving likelihood often merges meaningful units&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;OOV handling&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Almost none: every byte exists&lt;/td&gt;
&lt;td&gt;Possible: fully unseen combinations fall back to &lt;code&gt;[UNK]&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Typical models&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;GPT family, LLaMA&lt;/td&gt;
&lt;td&gt;BERT, DistilBERT&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;An intuitive comparison:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;For input &lt;code&gt;&quot;unbelievable&quot;&lt;/code&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;BPE, frequency-driven&lt;/strong&gt; → &lt;code&gt;[&quot;un&quot;, &quot;believ&quot;, &quot;able&quot;]&lt;/code&gt;
&lt;code&gt;un&lt;/code&gt; and &lt;code&gt;able&lt;/code&gt; are merged because they occur frequently; &lt;code&gt;believ&lt;/code&gt; is also frequent, though possibly less stable than &lt;code&gt;un&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;WordPiece, likelihood-driven&lt;/strong&gt; → &lt;code&gt;[&quot;un&quot;, &quot;##believ&quot;, &quot;##able&quot;]&lt;/code&gt;
The result looks similar, but &lt;code&gt;##believ&lt;/code&gt; carries &lt;code&gt;##&lt;/code&gt; because the model finds an attached form more probable than an independent word.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;The bigger difference is the vocabulary base:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;BPE begins at the &lt;strong&gt;byte level&lt;/strong&gt;, so its initial vocabulary contains all 256 byte values. WordPiece begins at the &lt;strong&gt;character level&lt;/strong&gt;, with Unicode characters plus common multi-character combinations. Therefore:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;BPE naturally includes every byte → any input can be assembled → no &lt;code&gt;[UNK]&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;WordPiece does not include every Unicode character → rare characters may become &lt;code&gt;[UNK]&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Later BERT versions addressed this with full-character coverage, but that is another story.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A blunt summary:&lt;/strong&gt; BPE is an illiterate statistician that cares only about “which two things occur together often.” WordPiece is half-literate: it knows what it does not know and leaves room for &lt;code&gt;[UNK]&lt;/code&gt;, but its splits have more linguistic intuition.
:::&lt;/p&gt;
&lt;h2&gt;Input Length and Output Vectors&lt;/h2&gt;
&lt;p&gt;Are there special cases where one word is embedded alone, or an entire document is embedded?&lt;/p&gt;
&lt;p&gt;What does the length of an input &lt;code&gt;token_id_list&lt;/code&gt; affect? Does it affect the sparseness or denseness of the output vector?&lt;/p&gt;
&lt;p&gt;:::note[Korewaxnne]
&lt;strong&gt;First, special cases do exist, and they are common.&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Single-word embedding:&lt;/strong&gt; when using an embedding model such as &lt;code&gt;text-embedding-3-small&lt;/code&gt;, input can absolutely be one word. Input &lt;code&gt;&quot;猫&quot;&lt;/code&gt;, and it returns one vector. A single word carries little information and usually retrieves poorly, but it is technically valid.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Whole-document embedding:&lt;/strong&gt; also valid, but constrained by length. Embedding models, like LLMs, have maximum input lengths—BGE-M3 has 8k tokens. Extra text is truncated or errors. Long documents are normally &lt;strong&gt;chunked&lt;/strong&gt;, then either pooled into one vector or retrieved through their individual vectors.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;So “usually a full sentence” is right, but it is &lt;strong&gt;not fixed&lt;/strong&gt;. Any length from one token to &lt;code&gt;max_tokens&lt;/code&gt; works.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;strong&gt;Now the main question: does input length affect output-vector sparseness or denseness?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;No.&lt;/strong&gt; It is an excellent question, but the direction is reversed.&lt;/p&gt;
&lt;p&gt;An output vector&apos;s &lt;strong&gt;dimension is fixed&lt;/strong&gt;—1024 for BGE-M3, 1536 for OpenAI&apos;s text-embedding-3-small. Whether input is one word or a thousand, output has that fixed length and values in every dimension, so it is dense. Sparse versus dense is determined by &lt;strong&gt;model structure&lt;/strong&gt;, not input length.&lt;/p&gt;
&lt;p&gt;Input length actually affects:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;What it affects&lt;/th&gt;
&lt;th&gt;Why&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Compute&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Longer input → more embedding lookups → slower and more expensive&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Output-vector quality&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Too short, one or two words, gives too little information; too long exceeds max tokens and loses information through truncation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Pooling choice&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;After chunking long input, average, weighted, or &lt;code&gt;[CLS]&lt;/code&gt; pooling changes the final vector&apos;s center of gravity&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;An intuition:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Input “猫” → one point.
Input “一只黑猫蹲在窗台上看雨” → another point.&lt;/p&gt;
&lt;p&gt;Both vectors are 1024-dimensional and occupy that same 1024-dimensional space. Neither differs in sparseness or denseness. The second simply carries more semantic information, so its neighbors understand its intended meaning better during retrieval.&lt;/p&gt;
&lt;p&gt;Your previous question—whether sparse and dense describe batch-vector spacing or values inside one vector—can now be answered: &lt;strong&gt;it is whether values in a single vector&apos;s dimensions are mostly zero.&lt;/strong&gt; Embedding-model output has no large number of zeros, so it is dense. BM25 output is almost entirely zero, with values only for matched terms, so it is sparse.
:::&lt;/p&gt;
&lt;h2&gt;Sparse vs. Dense: Make It Clear&lt;/h2&gt;
&lt;p&gt;My earlier understanding of sparse and dense now looks like this:&lt;/p&gt;
&lt;p&gt;Like a matrix, it is truly about whether values are zero. It is not whether a batch of vectors is distributed densely or sparsely in space; it is simply whether one vector contains many zeros.&lt;/p&gt;
&lt;p&gt;Sparse vectors are usually high-dimensional but use few dimensions. Dense vectors use nearly every dimension and vaguely express a “larger” semantic space.&lt;/p&gt;
&lt;p&gt;We can discuss something else here too.&lt;/p&gt;
&lt;h3&gt;What each suits&lt;/h3&gt;
&lt;p&gt;What scenarios suit sparse vectors?&lt;/p&gt;
&lt;p&gt;For example:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;A user talks with an LLM, while another LLM continuously summarizes facts and preferences from the conversation as memory.&lt;/li&gt;
&lt;li&gt;A user wants to quickly capture every article related to cats, using the keyword 猫.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Which suits dense or sparse vectors?&lt;/p&gt;
&lt;p&gt;Earlier, we mentioned that embedding a single term is possible, but normally it has too little semantic information for the vector to say anything useful and recall becomes difficult. Dense vectors are better at complex semantic expression; they handle complex query needs better, but can struggle with queries lacking semantics or context.&lt;/p&gt;
&lt;p&gt;BM25 and TF-IDF, by contrast, are designed for term retrieval. In scenario 2, the answer is almost instant.&lt;/p&gt;
&lt;p&gt;:::note[Korewaxnne]
Most of your intuition is right. Let me calibrate a few points.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Does BM25 have its own vector space?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Yes. Every term is a dimension. The dimension corresponding to “猫” has a value, while others are zero. Its vector space is an &lt;strong&gt;extremely high-dimensional sparse space whose dimensions are vocabulary terms&lt;/strong&gt;, perhaps 50,000 dimensions, while every vector has only a few nonzero values. That is why it counts as a sparse vector.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Which suits scenarios 1 and 2?&lt;/strong&gt;&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Scenario&lt;/th&gt;
&lt;th&gt;Matching type&lt;/th&gt;
&lt;th&gt;Better fit&lt;/th&gt;
&lt;th&gt;Why&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1. Conversation summaries → memories&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Semantic matching:&lt;/strong&gt; “the user likes cats” ≈ “they own a Ragdoll”&lt;/td&gt;
&lt;td&gt;Dense vectors&lt;/td&gt;
&lt;td&gt;Memories need to understand meaning rather than exact words. If a user says “I own a Ragdoll,” dense vectors can associate it with “cat”; sparse vectors cannot.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2. Search articles about “猫”&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Keyword matching:&lt;/strong&gt; title or text contains “猫”&lt;/td&gt;
&lt;td&gt;Sparse vectors, BM25&lt;/td&gt;
&lt;td&gt;The query is too short for a dense vector to say much; sparse vectors can hit the exact term immediately.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;But there is an implicit question worth expanding: why do dense vectors struggle with short queries?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;It is not because they are short, but because they &lt;strong&gt;lack context&lt;/strong&gt;. One word is too ambiguous:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;“猫” might mean the animal, feline species, cat food, cat videos, Tom and Jerry...&lt;/li&gt;
&lt;li&gt;“一只黑猫蹲在窗台上看雨” tells the model the approximate scene.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The more room the model has to infer, the more accurate semantic matching becomes. A one-word query gives it no room, so its vector does not know which direction to approach.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;How does production solve this? Through hybrid search.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Modern search engines almost never use one method only:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;query → BM25 (exact match) + dense vector (semantic expansion) → fused ranking → return
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;BM25 handles “do what was said”; dense handles “reason by analogy.” Their scores are weighted together—BM25 gets higher weight for short queries, dense gets more for long queries. This is also the complement of related-article recommendation discussed in your TF-IDF note.
:::&lt;/p&gt;
&lt;p&gt;From this perspective, memU and mem0 are both hybrid scenarios.&lt;/p&gt;
&lt;p&gt;They need dense embeddings and BM25 as a supplement. But how BM25 should be used has much to discuss. Is it simply the hybrid-search use shown above, or can it do something more interesting?&lt;/p&gt;
&lt;p&gt;When breaking down memU, we can capture how it uses BM25: simple hybrid search, or its own extension—[[What Is memU? Let&apos;s Break It Down (An Ongoing Series)|What Is memU? Let&apos;s Break It Down]].&lt;/p&gt;
&lt;h2&gt;Claude&apos;s Additions&lt;/h2&gt;
&lt;p&gt;I raised two questions at the beginning and forgot to ask them later, so I will add them here.&lt;/p&gt;
&lt;p&gt;:::note[Claude]&lt;/p&gt;
&lt;h3&gt;Why are some models good at dense vectors and others at sparse ones?&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Both architecture and pretraining matter, but the pretraining objective is decisive.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Architecturally, Transformer encoders such as BERT and BGE output fixed-dimensional vectors after attention plus pooling, with values in every dimension—naturally dense. BM25 is not a neural network at all. It works in a vocabulary-sized space, perhaps 50,000 dimensions, where only dimensions corresponding to words that appeared in a document are nonzero—naturally sparse.&lt;/p&gt;
&lt;p&gt;But neural networks can output sparse vectors too. SPLADE, for example, also uses a Transformer but adds a sparsification operation—log-saturate plus ReLU—at the output, forcing most dimensions to zero. It ultimately outputs sparse vocabulary-dimensional vectors. So Transformers are not inherently dense; output-layer design and training objectives decide it.&lt;/p&gt;
&lt;h3&gt;What is the objective of embedding pretraining, and how is it labeled?&lt;/h3&gt;
&lt;p&gt;The central idea is exactly what you guessed: &lt;strong&gt;bring similar semantics together and push different semantics apart.&lt;/strong&gt; Academically, this is &lt;strong&gt;contrastive learning&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Training constructs positive and negative pairs:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Sample type&lt;/th&gt;
&lt;th&gt;Meaning&lt;/th&gt;
&lt;th&gt;Sources&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Positive pairs&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Two semantically similar texts&lt;/td&gt;
&lt;td&gt;Query and a clicked document; question and answer; title and body; a sentence and its paraphrase&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Negative pairs&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Two semantically unrelated texts&lt;/td&gt;
&lt;td&gt;Random pairing, or hard negatives that look similar but are unrelated&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The loss function pulls positive-pair vectors closer and pushes negative-pair vectors apart.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Where do labels come from?&lt;/strong&gt; It is difficult, but many clever sources exist:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Natural supervision:&lt;/strong&gt; search-engine click logs, where searching X and clicking Y makes a positive pair; Q&amp;amp;A pairs; paper titles and abstracts&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Human annotation:&lt;/strong&gt; expensive but high quality, such as MS MARCO&apos;s human query-passage relevance labels&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Self-supervision:&lt;/strong&gt; adjacent paragraphs from one article become positives, while paragraphs from other articles become negatives, requiring no human labels&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;So embedding training does not need a similarity score manually marked for every pair of texts. It indirectly learns semantic-space structure through contrast among positive and negative pairs. This is why embedding models can keep improving in an era with enormous quantities of unlabeled text.
:::&lt;/p&gt;
</content:encoded></item><item><title>Travellin&apos; Cats in Germany: A Haven for Digital Cat Lovers</title><link>https://xnnehang.top/en/posts/travellin-cats-in-germany/</link><guid isPermaLink="true">https://xnnehang.top/en/posts/travellin-cats-in-germany/</guid><description>A game about finding one hundred hidden cats in a still illustration. They come in all shapes and sizes; each one lights up when found and answers with its own soothing meow.</description><pubDate>Tue, 14 Jul 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;img src=&quot;../../assets/img/travellin-cats-in-germany/PixPin_2026-07-14_20-18-58.jpg&quot; alt=&quot;Travellin&apos; Cats in Germany&quot; /&gt;&lt;/p&gt;
&lt;p&gt;It is a game about finding one hundred hidden cats in a still illustration. They come in all shapes and sizes; each one lights up when found, and every click is met with a soothing meow—never the same one twice.&lt;/p&gt;
&lt;p&gt;I found 85 of them in the first 25 minutes or so. I opened the game twice more afterward and found another three. I am no longer expecting to finish it.&lt;/p&gt;
&lt;p&gt;The background music deserves a special mention. It really is a little piece of peace: organ, acoustic guitar, flute, and lo-fi vocals that last exactly as long as they should.&lt;/p&gt;
&lt;p&gt;I was under quite a bit of stress the first time I opened it because of things happening outside the game. After playing for half an hour, though, the anxiety had noticeably eased.&lt;/p&gt;
&lt;p&gt;If you are the kind of person who adores cats through a screen, give it a try. Do not go in determined to beat it. Even if you only stay for the music, it will have been worth your time.&lt;/p&gt;
&lt;p&gt;I am grateful to it for giving me a peaceful night.&lt;/p&gt;
</content:encoded></item><item><title>Learning TF-IDF Again After Graduation</title><link>https://xnnehang.top/en/posts/tf-idf-and-bm25/</link><guid isPermaLink="true">https://xnnehang.top/en/posts/tf-idf-and-bm25/</guid><description>My plain-language explanation of TF-IDF, from terms and tokenization through TF, IDF, query scoring, BM25, and using it to recommend related posts on this blog. Apparently, it is much easier to pay back the debt of skipping NLP lectures once there is a reason to learn it.</description><pubDate>Sun, 12 Jul 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;img src=&quot;../../assets/img/about-comeback-learn-tfidf/PixPin_2026-07-12_23-13-36.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;[!NOTE]
&lt;strong&gt;AI collaboration disclosure:&lt;/strong&gt; Written by Xnne, with &lt;a href=&quot;https://github.com/xnne-bot&quot;&gt;Korewaxnne&lt;/a&gt;, an AI assistant, helping organize the structure and polish the language.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&amp;lt;iframe src=&quot;https://player.bilibili.com/player.html?bvid=BV1XT421Q7fw&quot; width=&quot;100%&quot; height=&quot;500&quot; frameborder=&quot;0&quot; allowfullscreen=&quot;true&quot;&amp;gt;&amp;lt;/iframe&amp;gt;&lt;/p&gt;
&lt;p&gt;:::note
I have returned almost all of my NLP knowledge to the teacher, apart from the part where we discussed &lt;em&gt;Lost in the Middle&lt;/em&gt;. The teacher had us find a paper or something, then try to explain it clearly on our own. They would also question us about what we had presented. That experience had a deep impact on me: how thoroughly do you need to understand something before you can explain it and answer questions about it? How do you find the right point between reductivism and staying on the surface? I can never repay Teacher Guo for this =-=.
:::&lt;/p&gt;
&lt;p&gt;The same old Feynman-learning-method opening: I will explain TF-IDF in my own plain language. There will not be much mathematics here.&lt;/p&gt;
&lt;p&gt;If you want a systematic and detailed explanation, watch the video above. It is very good.&lt;/p&gt;
&lt;h2&gt;TF-IDF&lt;/h2&gt;
&lt;h3&gt;Terms and tokenization&lt;/h3&gt;
&lt;p&gt;TF stands for Term Frequency.&lt;/p&gt;
&lt;p&gt;You can think of a term as a word. In English, a term is a word. In Chinese, there seems to be a subtle distinction between the two; look it up if you are interested. It is mainly about what counts as a stop word.&lt;/p&gt;
&lt;p&gt;For example, suppose we use jieba to segment this sentence:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;毕业后我搬回了老家。
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;After tokenization:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;毕业|后|我|搬回|了|老家
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;At first, assume we treat everything as a term.&lt;/p&gt;
&lt;p&gt;We can simply count the frequency of every term in each document chunk.&lt;/p&gt;
&lt;p&gt;We will find that stop words such as &lt;code&gt;了&lt;/code&gt;, &lt;code&gt;的&lt;/code&gt;, and &lt;code&gt;是&lt;/code&gt; occur very often.&lt;/p&gt;
&lt;p&gt;But nearly every article has these words. They only interfere with our calculation and provide no help at all. So TF-IDF usually does one thing right away.&lt;/p&gt;
&lt;p&gt;It turns the tokenized terms into this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;毕业|我|搬回|老家
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;After this cleanup, the text seems more concise without changing its meaning, and there is less to compute.&lt;/p&gt;
&lt;p&gt;But first, one thing needs to be clear: from TF-IDF&apos;s point of view, semantics do not exist. Whether something is a sentence or an article, it is only a collection of terms.&lt;/p&gt;
&lt;p&gt;It does not care who graduated or who moved back home. It only cares about graduation, moving, and hometown. These words are discrete, and their order does not matter.&lt;/p&gt;
&lt;p&gt;Why is it still so powerful? Its principle is actually very easy to understand.&lt;/p&gt;
&lt;p&gt;The remaining terms can tell us something.&lt;/p&gt;
&lt;h3&gt;TF: term frequency&lt;/h3&gt;
&lt;p&gt;The more often a term occurs in an article, the more relevant that article is to the term. That is &lt;strong&gt;Term Frequency&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;TF reflects how strongly an article is associated with a term. For example, if &lt;code&gt;深度学习框架&lt;/code&gt; has the highest TF in an article, that article is mainly about deep-learning frameworks.&lt;/p&gt;
&lt;h3&gt;IDF: inverse document frequency&lt;/h3&gt;
&lt;p&gt;Now consider this case.&lt;/p&gt;
&lt;p&gt;Suppose every article in our knowledge base is about deep-learning frameworks. Almost every article mentions them fairly often.&lt;/p&gt;
&lt;p&gt;If we want to retrieve something specific from this collection, is that phrase still useful as a signal?&lt;/p&gt;
&lt;p&gt;Put plainly: when a term appears at nearly the same frequency in every article, does it become as unhelpful in this collection as a stop word?&lt;/p&gt;
&lt;p&gt;But how should we clean it up? Would removing it outright be too crude? Is there a better way?&lt;/p&gt;
&lt;p&gt;Yes—and it is simple. We can assign every term a weight. If a term occurs frequently throughout the collection, lower its weight. Conversely, if it appears only in a particular subset of documents, raise its weight. This weight is called IDF—&lt;strong&gt;Inverse Document Frequency&lt;/strong&gt;—and it represents the value of a term.&lt;/p&gt;
&lt;p&gt;A term&apos;s IDF is relative. Mix an article about deep learning into a set of personal reflections, and deep-learning terminology becomes its best set of terms. Bury it among deep-learning articles, however, and IDF is what discovers and ranks the value of those terms.&lt;/p&gt;
&lt;h3&gt;Query scoring&lt;/h3&gt;
&lt;p&gt;How does TF-IDF work in an actual query?&lt;/p&gt;
&lt;p&gt;It normally needs a query.&lt;/p&gt;
&lt;p&gt;For example:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;我最后一次修改 XnneHangLab 是什么时候？
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That query is also split into terms and stripped of stop words:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;最后 | 一次 | 修改 | XnneHangLab | 什么时候
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then it calculates a TF-IDF score, which is really a summation.&lt;/p&gt;
&lt;p&gt;For &lt;strong&gt;each document and each term in the query&lt;/strong&gt;, it calculates TF × IDF, then &lt;strong&gt;adds them up&lt;/strong&gt;:&lt;/p&gt;
&lt;p&gt;$$Score = TF_1 \times IDF_1 + TF_2 \times IDF_2 + ... \text{(with len(query) terms)}$$&lt;/p&gt;
&lt;p&gt;The document with the highest score is the most relevant to the query, so we return it directly. I will not get into the specific normalization operations here.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;In more formal notation:&lt;/p&gt;
&lt;p&gt;$$
\text{Score}(D, Q) = \sum_{t \in Q} \text{TF}(t, D) \times \text{IDF}(t)
$$&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;$t$ = one term in the query&lt;/li&gt;
&lt;li&gt;$Q$ = the query&apos;s collection of terms&lt;/li&gt;
&lt;li&gt;$D$ = one document in the document collection&lt;/li&gt;
&lt;li&gt;$\sum$ = sum over every term in the query&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Recommending related posts with TF-IDF&lt;/h3&gt;
&lt;p&gt;https://xnnehang.top/&lt;/p&gt;
&lt;p&gt;My blog uses TF-IDF to recommend related posts as well.&lt;/p&gt;
&lt;p&gt;At this point, the principle is simple: turn an article into terms in the same way, then calculate it against every other article.&lt;/p&gt;
&lt;p&gt;The complexity is $O(N \times |\text{BlogTerms}|^2)$—that is, $n^2$—so it is not very high.&lt;/p&gt;
&lt;h3&gt;The relationship between BM25 and TF-IDF&lt;/h3&gt;
&lt;p&gt;BM25 is a variant of TF-IDF. The idea has not changed much, but the mathematics has changed a lot: normalization and so on. We do not need to worry about that; just think of it as a more accurate TF-IDF.&lt;/p&gt;
&lt;h3&gt;Limitations&lt;/h3&gt;
&lt;p&gt;We have already made this clear in the analysis: it sees only words, not semantics or word order.&lt;/p&gt;
&lt;p&gt;Still, it is pretty accurate for recommending related posts =-=.&lt;/p&gt;
&lt;p&gt;The charm of mathematics and all that.&lt;/p&gt;
&lt;h2&gt;Changes in tokenization&lt;/h2&gt;
&lt;p&gt;My understanding is that, after embeddings appeared, tokenization became segmentation → vectorization.&lt;/p&gt;
&lt;p&gt;But I wondered whether tokenization itself includes the segmentation step, or whether it specifically means the step from terms to embeddings.&lt;/p&gt;
&lt;p&gt;And what differs between tokenization for embeddings and tokenization before embeddings?&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;[!NOTE] Korewaxnne&lt;/p&gt;
&lt;p&gt;First, put the pipeline in order:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Raw text → **tokenize (split into tokens)** → convert to IDs → embedding lookup → vectors
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Tokenization &lt;strong&gt;only handles the first step&lt;/strong&gt;: splitting text into tokens. Going from terms to vectors is done later by embedding lookup; do not mix them up.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;strong&gt;1. Does tokenization itself include segmentation?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Yes. For Chinese, the central task of tokenization is segmentation.&lt;/p&gt;
&lt;p&gt;But the part you described as “term → embedding” is not tokenization. It is embedding lookup: a different step.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;strong&gt;2. What differs before and after embeddings?&lt;/strong&gt;&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Tokenization in the TF-IDF era&lt;/th&gt;
&lt;th&gt;Tokenization in the embedding era&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Granularity&lt;/td&gt;
&lt;td&gt;Whole words (word-level)&lt;/td&gt;
&lt;td&gt;Subwords, such as BPE / WordPiece&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Stop words&lt;/td&gt;
&lt;td&gt;Must be removed manually (&lt;code&gt;了&lt;/code&gt;, &lt;code&gt;的&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Do not remove them&lt;/strong&gt;—the model learns their use itself&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;OOV (out-of-vocabulary words)&lt;/td&gt;
&lt;td&gt;Fails immediately on an unseen word&lt;/td&gt;
&lt;td&gt;Can represent them by splitting into subwords, such as &lt;code&gt;Transformer&lt;/code&gt; → &lt;code&gt;Trans&lt;/code&gt; + &lt;code&gt;##former&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Output&lt;/td&gt;
&lt;td&gt;One word corresponds to one discrete ID&lt;/td&gt;
&lt;td&gt;One word may correspond to multiple subword IDs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Vocabulary size&lt;/td&gt;
&lt;td&gt;Tens to hundreds of thousands of words&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Fixed&lt;/strong&gt;, for example, BERT has about 30,000 subwords&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The core difference is &lt;strong&gt;granularity&lt;/strong&gt;. We used to split text into whole words; now we can split those words further. For example, &lt;code&gt;毕业&lt;/code&gt; may occur 1,000 times while &lt;code&gt;毕业典礼&lt;/code&gt; occurs only five times. With subword tokenization, a model can reuse what it learned from &lt;code&gt;毕业&lt;/code&gt; when it sees &lt;code&gt;毕业典礼&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
</content:encoded></item><item><title>gotcha.md: A Pitfall Handbook for Your Agent</title><link>https://xnnehang.top/en/posts/gotcha-agent-rules/</link><guid isPermaLink="true">https://xnnehang.top/en/posts/gotcha-agent-rules/</guid><description>Does your Agent keep repeating the same mistake before it finally remembers? A look at gotcha.md: which memories must be fully available as soon as a new session begins, and which can wait to be retrieved later?</description><pubDate>Tue, 07 Jul 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;img src=&quot;../../assets/img/gotcha-agent-rules/cover.jpeg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;:::note[Notes from Korewaxnne]
This article discusses an underestimated problem in Agent memory management: some knowledge should not take the retrieval route at all, but should instead be loaded in full when a new session starts. Take the &lt;code&gt;gotcha.md&lt;/code&gt; Xnne mentions: a project-root behavior-rules file that records what an Agent ought to know from the outset, rather than look up in a memory store only after making a mistake. It is unsuitable for retrieval because the query is hard to formulate, recall can never be guaranteed to be 100%, and unrelated queries can trigger behavioral conflicts or hallucinations. Beginning with a real pain point—repeating the same mistake—the article explores where gotchas come from, how to put them into practice, their relationship with Skills, and the boundary between “load everything up front” and “retrieve on demand.” If you are also wrestling with a forgetful Agent, perhaps it will offer a useful idea.
:::&lt;/p&gt;
&lt;h2&gt;Background&lt;/h2&gt;
&lt;p&gt;Claude Code has a feature called DreamMode: it consolidates Agents in the background &lt;strong&gt;while idle&lt;/strong&gt;, deduplicating, pruning, and maintaining memory files to keep cross-session memory tidy.&lt;/p&gt;
&lt;p&gt;On its workspace path, memU can likewise maintain a &lt;code&gt;gotcha.md&lt;/code&gt; in the project root while idle, and have &lt;code&gt;AGENTS.md&lt;/code&gt; reference it. This lets an Agent remember the pitfalls it has encountered even after a new session begins.&lt;/p&gt;
&lt;p&gt;If implementing that &lt;code&gt;while idle&lt;/code&gt; timing is difficult, it would still be useful to offer it as a CLI that a user can invoke manually first. Let us discuss why &lt;code&gt;gotcha.md&lt;/code&gt; is needed.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“Gotcha” roughly means a trap or a pitfall you have fallen into. I learned the term from &lt;a href=&quot;https://x.com/trq212/status/2033949937936085378&quot;&gt;Lessons from Building Claude Code: How We Use Skills&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;Why Do Pitfalls Keep Being Forgotten in New Sessions?&lt;/h2&gt;
&lt;p&gt;I often say things like this to my OpenClaw bot, and it forgets every time a new session starts:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;User: Remember to read the PR template before opening a PR next time, and put a cute Gitmoji in the title.
Agent: I got it.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The Agent writes this into a memory file. But it often only “remembers” it superficially—the memory &lt;strong&gt;may end up in a file the model does not load proactively, or be drowned among a pile of other facts&lt;/strong&gt;.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;For example, in OpenClaw, by default an Agent may save this rule in a diary for a particular day (&lt;code&gt;Diaries/2026-07-07.md&lt;/code&gt;), while more important points may go into &lt;code&gt;Memory.md&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;But reading either after a new session is disastrous. Older dates in the Diary directory are generally not read, and even gotchas mixed into &lt;code&gt;Memory.md&lt;/code&gt; perform poorly when they are interleaved with factual material.&lt;/p&gt;
&lt;p&gt;That is why, in this situation, gotchas need to be separated out into their own &lt;code&gt;gotcha.md&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;What Does &lt;code&gt;gotcha.md&lt;/code&gt; Record?&lt;/h2&gt;
&lt;p&gt;A gotcha is neither simply a user preference nor simply a fact. It is a one-line behavioral rule tied to a specific project:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;“Use Bun, not npm.”&lt;/li&gt;
&lt;li&gt;“PRs must follow the PR template.”&lt;/li&gt;
&lt;li&gt;“Run &lt;code&gt;make check&lt;/code&gt; before pushing.”&lt;/li&gt;
&lt;li&gt;“This project’s API returns XML, not JSON—check &lt;code&gt;Content-Type&lt;/code&gt; first.”&lt;/li&gt;
&lt;li&gt;“When a change only touches blog-content Markdown, do not run &lt;code&gt;pnpm build&lt;/code&gt; every time; it wastes too much time and too many tokens.”&lt;/li&gt;
&lt;li&gt;“Fix formatting and linting when you are about to merge; do not run checks twice after changing one line.”&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;They come from pitfalls an Agent encounters in conversation, corrections from the user, conventions in the project context, and lessons learned from Agent diaries.&lt;/p&gt;
&lt;h2&gt;When Is It Better to Separate Gotchas from User Preferences?&lt;/h2&gt;
&lt;p&gt;In an OpenClaw-like scenario, while working on a codebase, it is better to gather the pitfalls an Agent has encountered into a project-root &lt;code&gt;gotcha.md&lt;/code&gt;, then have &lt;code&gt;AGENTS.md&lt;/code&gt; point to it so that they do not disappear in a new session. [Read it through progressive disclosure.]&lt;/p&gt;
&lt;p&gt;Compared with scattering them across different dates or mixing them with other facts, centralizing them makes them faster to scan and less likely to be missed. It also treats them as knowledge a new session must understand in full, rather than knowledge to be recalled only by query.&lt;/p&gt;
&lt;p&gt;For casual conversation without a project—chat mode—there is no &lt;code&gt;gotcha.md&lt;/code&gt;, and none is necessary. Rules and restrictions would instead constrain the Agent’s own flexibility. User preferences are a better fit for that situation.&lt;/p&gt;
&lt;h2&gt;Where Can Gotchas Come From?&lt;/h2&gt;
&lt;p&gt;Gotchas have different sources and meanings on different paths:&lt;/p&gt;
&lt;h3&gt;Chat: Gotchas from Corrections&lt;/h3&gt;
&lt;p&gt;During development, when a user corrects an Agent in conversation, the rule implied by that correction is a gotcha.&lt;/p&gt;
&lt;p&gt;In an older chat-memorization system, it would roughly amount to adding a memory type called &lt;code&gt;gotcha&lt;/code&gt;, although it would overlap considerably with user preferences.&lt;/p&gt;
&lt;p&gt;But we cannot realistically run the whole old memorization process in OpenClaw. Having an LLM perform full memorization every time costs too many tokens and is too slow.&lt;/p&gt;
&lt;p&gt;The advantage of the auto-Dream approach is that it can analyze old sessions while idle—or when the user triggers it—without occupying active conversation time. Yet it can still make corrections persist across sessions.&lt;/p&gt;
&lt;h3&gt;Workspace: Gotchas from Project Context, Such as &lt;code&gt;CONTRIBUTING.md&lt;/code&gt; and Other Documents&lt;/h3&gt;
&lt;p&gt;For a newly encountered project, gotchas can be extracted from &lt;code&gt;CONTRIBUTING.md&lt;/code&gt; and &lt;code&gt;PR_TEMPLATE.md&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;They can also be extracted from the project’s CI workflows: recurring project-specific mistakes around tools such as Ruff and Pyright, for example.&lt;/p&gt;
&lt;p&gt;Still, the essence of a gotcha is correction after a mistake: make a mistake, receive a correction, then record it.&lt;/p&gt;
&lt;h3&gt;Skills: What Form Should Gotchas Take Inside a Skill?&lt;/h3&gt;
&lt;p&gt;This is a more forward-looking discussion.&lt;/p&gt;
&lt;p&gt;When enough gotchas accumulate around a topic, could they be &lt;strong&gt;synthesized into a new Skill&lt;/strong&gt;? The path would be:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Correction → gotcha → group similar gotchas → synthesize a Skill
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That lies further in the future, but the path from gotchas to Skills is natural.&lt;/p&gt;
&lt;p&gt;What remains worth discussing is which exerts stronger corrective force: &lt;strong&gt;the rules gathered together as gotcha entries&lt;/strong&gt;, or &lt;strong&gt;the rules divided by topic and placed into separate Skills&lt;/strong&gt;?&lt;/p&gt;
&lt;p&gt;And should references to Skills live in &lt;code&gt;AGENTS.md&lt;/code&gt; alongside other feature-oriented Skills, or inside &lt;code&gt;gotcha.md&lt;/code&gt; as an index?&lt;/p&gt;
&lt;p&gt;One advantage of extracting a Skill is portability: we can copy a desired topic—for example, a Python-project gotcha Skill—directly elsewhere, then create a &lt;code&gt;gotcha.md&lt;/code&gt; that references it. No reconstruction process is needed.&lt;/p&gt;
&lt;h2&gt;Output: &lt;code&gt;gotchas.md&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;Three paths flow into one file:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# Gotchas

## Project Rules

- Use Bun, not npm
- Run `make check` before pushing
- The API returns XML—always check Content-Type

## Workflow Rules

- PRs must follow the PR template
- Notify #dev before changing shared configuration
- Do not skip the smoke test for a canary deployment

## Agent Rules

- When the user says “remember,” actually persist it—do not merely say you will
- Check for duplicate entries before creating a memory
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;AGENTS.md&lt;/code&gt; references this file. Gotchas are short enough to load in every session—no retrieval is needed.&lt;/p&gt;
&lt;p&gt;This file is &lt;strong&gt;human-readable and editable&lt;/strong&gt;. Users can delete incorrect rules, add their own, and reorganize categories. A reflection step can merge new gotchas, resolve conflicts, and prune outdated rules—but the user makes the final decision.&lt;/p&gt;
&lt;h2&gt;Timing and Cost&lt;/h2&gt;
&lt;h3&gt;Core Principle: Do Not Intrude on the Existing Pipeline&lt;/h3&gt;
&lt;p&gt;Reflect &lt;strong&gt;does not run inside the &lt;code&gt;memorize-workspace&lt;/code&gt; pipeline&lt;/strong&gt;. It adds no cost to each conversation or each sync. The existing &lt;code&gt;memorize → preprocess → route → synthesize&lt;/code&gt; flow remains unchanged.&lt;/p&gt;
&lt;h3&gt;Following DreamMode’s Approach&lt;/h3&gt;
&lt;p&gt;Claude Code’s DreamMode triggers &lt;strong&gt;while idle&lt;/strong&gt; when:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;At least 24 hours have passed since the previous cleanup;&lt;/li&gt;
&lt;li&gt;At least five sessions have accumulated;&lt;/li&gt;
&lt;li&gt;No other cleanup task is running.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Reflect adopts a similar strategy—&lt;strong&gt;rather than extracting gotchas after every conversation, it waits and consolidates them in batches&lt;/strong&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Day 1: The user runs memorize-workspace three times
       (normal sync; no reflect triggered)

Day 1 night / while idle:
  memu reflect
    ├── Read existing memory files, Skill files, and workspace resources
    ├── Extract gotchas (corrections, project conventions, pitfalls)
    ├── Merge with existing gotchas.md, deduplicate, and resolve conflicts
    └── Write a clean gotchas.md

Day 2: A new session starts; AGENTS.md references gotchas.md
       → the Agent reads all rules
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It is worth considering whether the material to consolidate should be memory files, Skills, and workspace resources, or only the most recent sessions themselves. For now, I lean toward the latter, because mistakes and corrections are easier to identify from session context itself.&lt;/p&gt;
&lt;h3&gt;Cost&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;One reflection = two or three LLM calls: read existing gotchas, consolidate new sources, then merge and write the output. For overlong contexts, filtering must be considered. Gotchas are often near the surface—in the user’s messages and the first few lines of the Agent’s messages, often while it is apologizing. For long contexts, keeping roughly 300 tokens from each message should be enough.&lt;/li&gt;
&lt;li&gt;The frequency is low—once a day, perhaps configurable, or manually triggered—so it does not affect normal-use speed or token consumption.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The simplest implementation is an independent &lt;code&gt;memu reflect&lt;/code&gt; command that the user runs whenever they feel cleanup is due. Automated triggering, with DreamMode-like conditions, can come later.&lt;/p&gt;
&lt;h2&gt;Why Is This a Good Fit for memU, and Why Does memU Need It?&lt;/h2&gt;
&lt;p&gt;memU has recently been specializing in workspaces.&lt;/p&gt;
&lt;p&gt;Rule-like entries such as gotchas are ill-suited to query-based retrieval: they can recall a great deal of irrelevant information, but more importantly, in a project a gotcha is not something that only needs to be understood when it happens to be used.&lt;/p&gt;
&lt;p&gt;It is a major premise—something an Agent should know &lt;strong&gt;from the very beginning&lt;/strong&gt; in that workspace.&lt;/p&gt;
&lt;p&gt;Gotcha specialization neatly addresses a weakness in memU’s workspace experience. For workspace scenarios, it can easily improve the experience and save tokens.&lt;/p&gt;
&lt;p&gt;Moreover, memU is already familiar with this kind of reflection work. Many prompts for the old memorization system’s memory types can serve as references.&lt;/p&gt;
&lt;h2&gt;What Else Can Be Done Beyond Gotchas?&lt;/h2&gt;
&lt;p&gt;Auto Dream mode can organize many other things as well.&lt;/p&gt;
&lt;p&gt;For example, it can organize memory files, Skills, and workspace resources, then produce items similar to &lt;code&gt;gotcha.md&lt;/code&gt; on demand and reference them directly in &lt;code&gt;AGENTS.md&lt;/code&gt;. They become prerequisite knowledge rather than knowledge that lives in an on-demand knowledge base.&lt;/p&gt;
&lt;p&gt;Another, more abstract but potentially token-saving document would guide an Agent’s understanding of project structure.&lt;/p&gt;
&lt;p&gt;For example, a project may have a frontend, backend, launcher, and CI, yet a particular change may be confined to just one side. When first encountering the project, however, an Agent can still waste many tokens trying to understand the whole thing.&lt;/p&gt;
&lt;p&gt;But this is difficult to do well. It can easily go beyond guidance and become a document that is stale or wrong. I do not yet have a clearer idea for it.&lt;/p&gt;
</content:encoded></item><item><title>Starting with How We Use Skills: What Are Progressive Disclosure and Task Decomposition, and What Do I Want to Explore?</title><link>https://xnnehang.top/en/posts/progressive-disclosure-and-novel-agent/</link><guid isPermaLink="true">https://xnnehang.top/en/posts/progressive-disclosure-and-novel-agent/</guid><description>Reading notes on How We Use Skills: when you cannot put everything in front of an Agent at once, how do you keep it effective? Progressive Disclosure and Task Decomposition.</description><pubDate>Fri, 03 Jul 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;:::note[Notes from Korewaxnne]
This is one of Xnne’s reading notes, on Anthropic’s well-known &lt;em&gt;Lessons from Building Claude Code: How We Use Skills&lt;/em&gt;. But instead of obediently writing a conventional response, he starts with “progressive disclosure,” wanders into a novel Agent’s symbolic abstract language, and even detours into how the opening of &lt;em&gt;Six Records of a Floating Life&lt;/em&gt; could be broken down with a description chain. Halfway through, Claude Fable 5 pulled him into an argument; the exchange ended up clarifying the boundary between progressive disclosure and task decomposition completely. A typical Xnne-style divergence: start from one point, excavate a whole field of things he truly cares about, then argue the concepts until they become as clear as possible.
:::&lt;/p&gt;
&lt;h2&gt;Some Digressions&lt;/h2&gt;
&lt;p&gt;I plan to read &lt;a href=&quot;https://x.com/trq212/status/2033949937936085378&quot;&gt;Lessons from Building Claude Code: How We Use Skills&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Here is a Chinese translation by DeepSeek: &lt;a href=&quot;https://github.com/MrXnneHang/xnnehang.top.factory/blob/main/lessons-building-claude-code-how-we-use-skills-cn.md&quot;&gt;lessons-building-claude-code-how-we-use-skills-cn.md&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;But because of the special nature of submodules, GitHub cannot render images stored in another repository directly. So I can only pull it down and sync the submodule locally to view it.&lt;/p&gt;
&lt;p&gt;Because of copyright concerns, I cannot repost someone else’s article directly on my blog. My &lt;a href=&quot;https://xnnehang.top/&quot;&gt;blog&lt;/a&gt; has a relatively permissive license, &lt;a href=&quot;https://creativecommons.org/licenses/by-nc-sa/4.0/&quot;&gt;CC BY-NC-SA 4.0&lt;/a&gt;: non-commercial reuse is fine as long as there is attribution.&lt;/p&gt;
&lt;h2&gt;What Do I Want to Know? Ask First.&lt;/h2&gt;
&lt;p&gt;Ever since I realized that I might have ADHD, I have made a habit of asking questions first. If I do not figure out what I want to know, I will probably never finish reading an article like this.&lt;/p&gt;
&lt;h2&gt;What Exactly Is Progressive Disclosure?&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;There is a small issue with this definition itself, though it is not a big one. See Fable 5’s correction in the final section.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I think progressive disclosure can be used for more than Skill design and loading. To me, it is closer to a design philosophy: a concrete magic play built on understanding a model’s capabilities.&lt;/p&gt;
&lt;p&gt;Once you know where a model’s ability reaches its limit, it is about taking work that cannot be finished in one input-output pass, splitting it into step-by-step inputs and outputs, and lowering the threshold for the first step and every following step. At each step, you try to bring out the model’s full ability.&lt;/p&gt;
&lt;p&gt;For example, in something I wrote yesterday—[[memU&apos;s Architectural Shift Through the Eyes of a Consumer-Facing Developer]]—I mentioned this:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Earlier I mentioned giving reasoning capability to an agent loop, allowing the agent to query repeatedly. But an agent’s ability degrades in long contexts. I did something similar in XnneHangLab: I relied on the agent itself to retrieve and extract memories. After a long conversation, tool-calling execution rates fell greatly, as did the trigger rate for Skills with long tool chains. In the end, I had to switch to several step-by-step LLM calls by splitting tool calls. An agent loop merges multiple steps into a single decision at the first step. Does that make the first step too difficult?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;At the time, I accidentally came up with a solution to that one. It was actually an expression of progressive-disclosure thinking.&lt;/p&gt;
&lt;p&gt;And in the blog post I am reading this time, it is a best practice for progressive disclosure in Skills.&lt;/p&gt;
&lt;p&gt;But I do not want to see only an engineering pattern for Skills. I want to extend it.&lt;/p&gt;
&lt;h2&gt;What Do I Want to Understand and Extend?&lt;/h2&gt;
&lt;h3&gt;How to Understand a Project Through Progressive Disclosure&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;This is also what memU is doing during its refactor.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;For example, can it guide how an Agent—or a group of Agents—should explore and break down a project, then form path files that can rapidly guide thinking the next time?&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Why not record everything, instead of only doing agentic search/exploration?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h4&gt;It Becomes Stale&lt;/h4&gt;
&lt;p&gt;Records are usually fragmented and documentation-like, organized as a folder tree. That means they can easily become stale once written. Maintaining docs usually requires a maintainer to remember every piece of them deeply, but LLM-written docs generally cannot achieve that.&lt;/p&gt;
&lt;h4&gt;Annotation-Style Docs Are Not Needed&lt;/h4&gt;
&lt;p&gt;Or perhaps docs are generated automatically from docstrings. But for an Agent, such docs are garbage docs. For ordinary people, reading code without comments or docstrings is painful because they need to read many related parts before they understand the relationship between functions and classes.&lt;/p&gt;
&lt;p&gt;But for an Agent, comments are optional because it can understand uncommented code directly; its understanding window is much larger than a normal person’s. For an Agent, incorrect and stale comments or docstrings are the real hallucinations, the things that cause pain.&lt;/p&gt;
&lt;hr /&gt;
&lt;h3&gt;Applying Progressive-Disclosure Thinking to a Novel Agent&lt;/h3&gt;
&lt;p&gt;For example, could it guide the construction of special Agents such as a novel-writing Agent?&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;What is the fundamental difference between an Agent that writes novels and one that writes code?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Setting aside other independent Agents used for outlining and reviewing when writing a long novel, let us discuss only the ghostwriter: the Agent responsible for turning an outline or idea into an actual novel.&lt;/p&gt;
&lt;h3&gt;Style and Pacing&lt;/h3&gt;
&lt;p&gt;For novels, style and pacing are the most magical things.&lt;/p&gt;
&lt;p&gt;They are abstract. They may include describing an environment as if moving a film camera, emphasizing a “sense of imagery.”&lt;/p&gt;
&lt;p&gt;They also include ensuring that, after reading a character’s speech or inner thoughts, a voice remains in the reader’s mind—making each character’s language distinct.&lt;/p&gt;
&lt;p&gt;Writing must be able to move readers’ emotions. It needs empathy; its language cannot be too plain, and it must carry feeling. Perhaps humor, perhaps intensity. This sounds a little abstract, so here is an example:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;In the winter of the guǐwèi year of the Qianlong reign, on the twenty-second day of the eleventh month, I was living in an age of peace, born into a family of robes and caps, beside Canglang Pavilion in Suzhou. Heaven had been exceedingly generous to me. Su Shi said, “Events are like a spring dream, leaving no trace.” If I did not set them down in writing, I would fail Heaven’s generosity. Thinking that &lt;em&gt;The Ospreys&lt;/em&gt; stands at the head of the Three Hundred Poems, I therefore place husband and wife at the beginning of this volume, and let the rest follow in order. I regret that I missed much schooling in youth and know only a little; I merely record what truly happened. To demand that I verify its grammar would be like asking a bright mirror to inspect dirt.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I do not ask every reader to feel it, but a work must have its own readership.&lt;/p&gt;
&lt;p&gt;There are also some quantitative measures, depending on the platform. Some want long paragraphs and little dialogue, calling it slow pacing. Others want short paragraphs and a high proportion of dialogue, calling it fast pacing.&lt;/p&gt;
&lt;p&gt;Slow pacing especially considers cinematic, shot-like narration and the cultivation and movement of readers’ emotions.&lt;/p&gt;
&lt;p&gt;Fast pacing especially considers character dialogue, contrast in personality, and the tension of the plot.&lt;/p&gt;
&lt;p&gt;And if you are writing a long novel, the Agent must also keep its understanding of character personality and language, relationships, and storylines from drifting over a long text.&lt;/p&gt;
&lt;p&gt;How hard is a novel Agent to build? Put simply, if an Agent can write long novels well, there is basically nothing that can stump Agents themselves.&lt;/p&gt;
&lt;p&gt;The difficulty of writing a novel is that every ability mentioned above must be present and must perform well at the same time.&lt;/p&gt;
&lt;p&gt;Unlike a coding Agent, which loads one Skill at a time, a novel Agent wants to load every Skill at once. That inevitably runs into the limitation mentioned in &lt;a href=&quot;https://x.com/trq212/status/2033949937936085378&quot;&gt;Lessons from Building Claude Code: How We Use Skills&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;When you give an Agent many complex and hard-to-understand rules at once, it loses its original flexibility and performs less well.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/img/lessons-building-claude-code-how-we-use-skills/06-avoid-railroading.jpg&quot; alt=&quot;A comparison between an overly rigid six-step cherry-pick workflow and better flexible instructions—the former hard-codes every step, while the latter states intent and lets Claude adapt&quot; /&gt;&lt;/p&gt;
&lt;p&gt;The better approach described there is to tell an Agent which necessary elements an elegant approach should include, rather than spelling out every step of the path you think is elegant. Come on—do you think you understand Git usage and workflow better than Claude Opus or Fable? You only need to tell it what deserves attention in your repository. For example, you expect commit messages to be entirely in English and include cute gitmoji. Add that, and you get cute gitmoji every time.&lt;/p&gt;
&lt;p&gt;So a novel Agent still has a long way to go. Perhaps I took the wrong road from the beginning, when I built complex Skills.&lt;/p&gt;
&lt;p&gt;But when I chatted with a roommate, we seemed to touch on some progressive-disclosure design.&lt;/p&gt;
&lt;p&gt;We stopped pursuing a complete article in one pass—or, more precisely, stopped trying to write the body immediately. Instead, we used multiple steps. How exactly?&lt;/p&gt;
&lt;p&gt;First, establish a symbolic abstract language.&lt;/p&gt;
&lt;p&gt;This symbolic language includes descriptive techniques, descriptive objects, and descriptive themes.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;In the winter of the guǐwèi year of the Qianlong reign, on the twenty-second day of the eleventh month, I was living in an age of peace, born into a family of robes and caps, beside Canglang Pavilion in Suzhou. Heaven had been exceedingly generous to me. Su Shi said, “Events are like a spring dream, leaving no trace.” If I did not set them down in writing, I would fail Heaven’s generosity.&amp;lt;br&amp;gt;
Thinking that &lt;em&gt;The Ospreys&lt;/em&gt; stands at the head of the Three Hundred Poems, I therefore place husband and wife at the beginning of this volume, and let the rest follow in order. I regret that I missed much schooling in youth and know only a little; I merely record what truly happened. To demand that I verify its grammar would be like asking a bright mirror to inspect dirt.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Still this passage.&lt;/p&gt;
&lt;p&gt;It can be split into two segments for generation.&lt;/p&gt;
&lt;p&gt;Turn it into a description chain like this:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I -&amp;gt; lyricism@origins, “Events are like a spring dream, leaving no trace”【slow】~desolation -&amp;gt; self-mockery【fast】~humor&amp;lt;br&amp;gt;
I -&amp;gt; discussion@classical tradition (“The Ospreys”) -&amp;gt; narration@placing husband and wife at the volume’s beginning【slow】&lt;s&gt;solemnity -&amp;gt; self-mockery@grammar and learning&lt;/s&gt;humor&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Of course, this description chain is a little abstract. I made it up from memory; my roommate was mainly researching it at the time, and I am truly not very good at specifying rules like this.&lt;/p&gt;
&lt;p&gt;In any case, first generate this kind of description chain to avoid needing a mass of Skills to constrain an unstable writing style at once.&lt;/p&gt;
&lt;p&gt;The intention is to specify narrative pacing and style in this way. I remember my roommate adding an example for every technique.&lt;/p&gt;
&lt;p&gt;Then the LLM needs to be able to encode—abstracting a novel into this kind of description chain—and turn a description chain back into a novel. But not merely restore it: it must even change the phrasing, then reread it, to verify that the LLM truly understands that style and pacing itself.&lt;/p&gt;
&lt;h2&gt;Start Reading, and Put Attention Where I Want It&lt;/h2&gt;
&lt;p&gt;What a Skill is and the specific categories of Skills.&lt;/p&gt;
&lt;p&gt;I skipped almost all of it. I could not see anything at a glance. I concede it: I really do have a reading disorder.&lt;/p&gt;
&lt;h3&gt;How to Write Skills&lt;/h3&gt;
&lt;h4&gt;1. Do Not Write the Obvious.&lt;/h4&gt;
&lt;p&gt;As I just mentioned, do not think you understand Git usage and conventions better than Anthropic does.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/img/lessons-building-claude-code-how-we-use-skills/06-avoid-railroading.jpg&quot; alt=&quot;A comparison between an overly rigid six-step cherry-pick workflow and better flexible instructions—the former hard-codes every step, while the latter states intent and lets Claude adapt&quot; /&gt;&lt;/p&gt;
&lt;h4&gt;2. Build a Gotchas Guide&lt;/h4&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/img/lessons-building-claude-code-how-we-use-skills/04-gotchas-section.jpg&quot; alt=&quot;The Gotchas section of a billing-lib SKILL.md grows progressively from Day 1 to Week 2 to Month 3, adding one new pitfall each time&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Claude can make mistakes with personalized libraries or requirements, so tailoring gotchas for such a library pays off well.&lt;/p&gt;
&lt;p&gt;One thing that sometimes drives me crazy about OpenClaw is that I ask it to write down a gotcha again and again, but I cannot remember why it keeps repeating the same mistake. Did it write the rule into some unknown corner, or does it simply never reread its written rules after every session refresh?&lt;/p&gt;
&lt;p&gt;Add one entry after every pitfall, but those gotchas must be retrievable. Otherwise, the same mistake will still happen.&lt;/p&gt;
&lt;h4&gt;3. Make Good Use of Progressive Disclosure in the File System&lt;/h4&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/img/lessons-building-claude-code-how-we-use-skills/05-progressive-disclosure.jpg&quot; alt=&quot;A queue-debugging Skill folder centered on SKILL.md, linking to spoke files—stuck-jobs.md, dead-letters.md, retry-storms.md, and consumer-lag.md—plus a symptom-to-file lookup table&quot; /&gt;&lt;/p&gt;
&lt;p&gt;a. Use references instead of loading a complete Skill.
b. If Markdown output is needed, use fill-in-the-blank templates instead of generating everything from scratch. Allow copying and pasting a template.&lt;/p&gt;
&lt;h4&gt;4. Extract Inputs That Need User Answers from a Skill into config.json.&lt;/h4&gt;
&lt;p&gt;Some Skills may need the user to choose one or more input sources, like this:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/img/progressive-disclosure/config-json-example.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Something like this should be extracted into config.json rather than entering the context directly with Markdown.&lt;/p&gt;
&lt;h4&gt;5. A Description Is Not a Summary of Tool Contents; It Describes When and Why to Trigger.&lt;/h4&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/img/lessons-building-claude-code-how-we-use-skills/08-description-field.jpg&quot; alt=&quot;A comparison between two babysit-pr SKILL.md descriptions: the left is a vague summary; the right is trigger-oriented and lists phrases such as “babysit,” “watch CI,” and “make sure this lands”&quot; /&gt;&lt;/p&gt;
&lt;h4&gt;6. Prepare Common Scripts Ahead of Time Instead of Writing Them When Needed.&lt;/h4&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/img/lessons-building-claude-code-how-we-use-skills/10-helper-functions.jpg&quot; alt=&quot;A lib/signups.py file with helper functions including fetch, by_referrer, and by_landing_page; each function records pitfalls in its docstring&quot; /&gt;&lt;/p&gt;
&lt;p&gt;This is especially obvious with web-based GPT. If you ask GPT to write or edit a docx directly, it will often spend more than ten minutes writing a terrible Python-based script to read and modify the docx, then mangle your document completely.&lt;/p&gt;
&lt;p&gt;But if you use Claude Desktop in Cowork mode with a docx Skill installed in advance, it is at least fast and stable. It avoids writing a Python script from scratch every time.&lt;/p&gt;
&lt;h4&gt;7. Should Skills Depend on One Another?&lt;/h4&gt;
&lt;p&gt;Should we make the Skill ecosystem resemble PyPI?&lt;/p&gt;
&lt;p&gt;Could packages depend on other packages?&lt;/p&gt;
&lt;p&gt;It sounds great, but as already mentioned above:&lt;/p&gt;
&lt;p&gt;Agent capabilities vary and will only grow stronger. Some old Skills and rules work well now, but may become prompts and constraints that actively make things worse later. So Skills should be understood inside and out. Skills you wrote yourself can depend on one another, but it is best not to depend on other people’s Skills.&lt;/p&gt;
&lt;h2&gt;Finished Reading&lt;/h2&gt;
&lt;p&gt;It gave me some things to think about.&lt;/p&gt;
&lt;p&gt;But most importantly, it gave me an opportunity to think about what progressive disclosure is and where I want to extend it.&lt;/p&gt;
&lt;p&gt;That is: progressive disclosure aimed at understanding projects, and progressive disclosure aimed at novel Agents.&lt;/p&gt;
&lt;p&gt;Everything else was more like review and confirmation, turning formerly vague intuitions into definite concepts.&lt;/p&gt;
&lt;p&gt;There were small gains too. For example, I can now clearly answer whether Skills should depend on one another and whether they should become a PyPI-like ecosystem.&lt;/p&gt;
&lt;p&gt;Previously, that should have been a no.&lt;/p&gt;
&lt;h2&gt;A Correction from Fable 5: Confusing Progressive Disclosure with Task Decomposition&lt;/h2&gt;
&lt;p&gt;Here is Claude Fable 5’s correction of the ideas in my post:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Enjoyable read — it&apos;s doing the thing good reading notes do: using the source as a launchpad rather than summarizing it. My honest assessment of his core claim:&lt;/p&gt;
&lt;p&gt;His view is right in spirit, but stretches the term. He defines progressive disclosure as &quot;breaking a task too big for one pass into step-by-step inputs and outputs.&quot; That&apos;s actually task decomposition, a sibling technique. Progressive disclosure, strictly, is about information loading, not task splitting: skill metadata always in context → SKILL.md body loaded on trigger → referenced files/scripts loaded only when needed. The distinction matters because they fix different failure modes. PD fixes attention dilution (context stuffed with irrelevant rules degrades everything). Decomposition fixes capability limits (one pass can&apos;t hold the whole task). His memU example — splitting tool calls across multiple LLM calls after long-context degradation — is decomposition. Both fight the same enemy, so his generalization is useful intuition, just imprecise vocabulary.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Where he&apos;s clearly right:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Skills as &quot;what to pay attention to&quot; rather than step-by-step instructions&lt;/strong&gt; — this matches how skills actually work best. Over-specified procedures turn into straitjackets as models improve, which is also why his answer to &quot;should skills depend on each other like PyPI&quot; (no) is sound.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Gotchas being useless unless recalled&lt;/strong&gt; — correct diagnosis. A gotcha outside the retrieval path (trigger description or always-loaded context) may as well not exist.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The novel-agent observation is his sharpest&lt;/strong&gt; — coding constraints are modular (load one skill at a time), but style/pacing/voice are cross-cutting — they must apply to every sentence simultaneously. That&apos;s a real architectural difference, well stated.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Where I&apos;d push back:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&quot;Comments are optional for agents, docs are garbage&quot; overshoots.&lt;/strong&gt; Stale docs cause hallucination, yes — but the fix is docs that are cheap to keep true (curated, high-level, intent-focused), not no docs. Agents still pay real exploration cost without a map, which his own &quot;path files&quot; idea implicitly admits.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The description-chain idea is promising but it&apos;s an intermediate representation with staged generation, not PD.&lt;/strong&gt; Its hard problem: style lives partly in exactly what a symbolic chain can&apos;t capture. The encode→decode→verify round-trip is the right test for that, though — good instinct.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Net:&lt;/strong&gt; right philosophy, blurry taxonomy, and one or two ideas worth an actual experiment.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr /&gt;
&lt;p&gt;Put simply, my intuition was right, but my phrasing and definition were not precise enough.&lt;/p&gt;
&lt;p&gt;I defined “Progressive Disclosure” (PD) as “splitting a large task that cannot be handled in one interaction into step-by-step inputs and outputs.”&lt;/p&gt;
&lt;p&gt;In fact, I confused &lt;strong&gt;Task Decomposition&lt;/strong&gt; with &lt;strong&gt;Progressive Disclosure (PD)&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Task Decomposition&lt;/strong&gt; addresses &lt;strong&gt;the limits of an Agent’s capability in a single pass&lt;/strong&gt;: when one LLM call cannot take in the whole task, split it into several interactions or LLM calls.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Progressive Disclosure&lt;/strong&gt; addresses &lt;strong&gt;attention dilution, distraction, and conflicts caused by excessive redundant rules in context&lt;/strong&gt;: put only a metadata index in context, load the specific &lt;code&gt;SKILL.md&lt;/code&gt; only when it is triggered, then read referenced scripts or files when further needed.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Both aim to resist the degradation of large-model capability, so this instinct to extend them was a good one. I was simply not rigorous enough with the terminology. I originally planned to generalize progressive disclosure, but generalized it so far that I accidentally uncovered another engineering principle I did not originally understand: task decomposition.&lt;/p&gt;
</content:encoded></item><item><title>memU&apos;s Architectural Shift Through the Eyes of a Consumer-Facing Developer</title><link>https://xnnehang.top/en/posts/memu-adr0007-ce-duan-perspective/</link><guid isPermaLink="true">https://xnnehang.top/en/posts/memu-adr0007-ce-duan-perspective/</guid><description>memU ADR 0007 overturns the earlier LLM mode: thoughts from a consumer-product developer and emotional-companion perspective.</description><pubDate>Thu, 02 Jul 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;memU ADR 0007 Through the Eyes of a Consumer-Facing Developer&lt;/h2&gt;
&lt;p&gt;The reason for this started yesterday, while I was breaking down memU&apos;s source code in [[What Is memU? Let&apos;s Break It Down (An Ongoing Series)|What Is memU? Let&apos;s Break It Down]]. I found that memU&apos;s newly released ADR 0007 architecture document had almost completely overturned what I had broken down and understood =-=.&lt;/p&gt;
&lt;p&gt;So I stopped.&lt;/p&gt;
&lt;p&gt;And I talked with my mentor:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I read ADR 0007. It unifies the former RAG/LLM dual retrieval modes into hybrid search (embedding + BM25). I understand the benefits: the retrieval path no longer calls an LLM, so speed and cost improve substantially.&amp;lt;br&amp;gt;
But I have a concern. The old LLM mode&apos;s ranking had reasoning ability—for example, it could judge that an item was logically related to a query even when the keywords did not match. LLMs themselves keep improving, so retrieval could improve alongside the models. Once it switches to hybrid search, does this part become fixed?&amp;lt;br&amp;gt;
Also, are there plans to restore LLM reasoning to the retrieval path in some other way later, such as through a reranker?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;That expresses how much I liked the LLM mode design =-=. I like LLM retrieval, but it has been entirely removed in the new architecture.&lt;/p&gt;
&lt;p&gt;Later, they asked me what I thought of this architectural change from a user&apos;s perspective.&lt;/p&gt;
&lt;p&gt;But I am a somewhat unusual user. More exactly, I am a consumer-facing developer. I wrap projects like memU into my own project, then pass them on to users without development backgrounds. I am also my own user. I keep XnneHangLab open while playing galgames.&lt;/p&gt;
&lt;p&gt;So my perspective is a little strange.&lt;/p&gt;
&lt;h3&gt;Can an agent loop replace LLM mode?&lt;/h3&gt;
&lt;p&gt;Earlier, the idea was to hand reasoning to an agent loop and let the agent query multiple times. But agents lose ability in long contexts. I did something similar in XnneHangLab, relying on an agent&apos;s own ability for memory retrieval and extraction. After long conversations, tool-call completion rates dropped greatly, and skills with long tool chains triggered less often. Eventually I had to switch to several LLM calls in separate steps, breaking apart tool calls. Does merging multiple steps into an agent loop&apos;s first decision make that first step too difficult?&lt;/p&gt;
&lt;h4&gt;White boxes and unspeakability&lt;/h4&gt;
&lt;p&gt;Many consumer users want memory retrieval to be a white box: they want to see how their waifu&apos;s memory was awakened. memU&apos;s old LLM mode could provide a complete reasoning chain, but after ADR 0007 retrieval becomes semantic-similarity ranking plus keyword matching. Semantic similarity has a kind of unspeakability: it can only say “these two are related,” not “what is their relationship?”&lt;/p&gt;
&lt;p&gt;That black box also means later optimization can only be judged through benchmarks, not analyzed and improved through a reasoning path.&lt;/p&gt;
&lt;h3&gt;Why not distinguish retrieval by scene?&lt;/h3&gt;
&lt;p&gt;The conflict behind the refactor is that workspace and chat are two different input and retrieval scenarios. Supporting both LLM mode and RAG mode means maintaining isolated retrieval systems, which costs too much. So ADR 0007 unifies them under hybrid search and maintains only one retrieval path.&lt;/p&gt;
&lt;p&gt;The architecture is tidier. But architectural tidiness and functional experience are often opposed. &lt;em&gt;Red Dead Redemption 2&lt;/em&gt; is not great only for its architecture and spirit; it is great because countless details create immersion. ADR 0007 makes one clean cut for tidiness, and at the same time cuts away many details that took a long time to polish.&lt;/p&gt;
&lt;p&gt;These were originally different scenarios. While writing code, a workspace can stay open constantly; in a role-playing conversation, a workspace is unnecessary. Why must they use the same retrieval method?&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;But as a framework layer, perhaps memU really should prioritize architectural tidiness. Leave complex features to consumer-product developers, such as Open-LLM-Vtuber and XnneHangLab.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;Two paths, two purposes&lt;/h3&gt;
&lt;p&gt;Chat follows the companionship path—personalization—while workspace follows project understanding—tooling. For chat, the LLM mode&apos;s reasoning chain and explainability are core value and should remain. Let the two paths go their own way; the architecture only needs to isolate them well.&lt;/p&gt;
&lt;p&gt;This is fundamentally a product-positioning question: is memU only a code-memory tool for developers, or a more general memory project? I think memU can absolutely generalize—even to embodied-intelligence products when they eventually arrive. It need only leave room for other scenarios; it does not need to implement them immediately.&lt;/p&gt;
&lt;h3&gt;The consumer-user perspective&lt;/h3&gt;
&lt;p&gt;I develop XnneHangLab. Its users are consumer users without development backgrounds; they even need to be taught how to buy a DeepSeek API. At least 80% are like this.&lt;/p&gt;
&lt;p&gt;Before memU v1.0, LLM mode needed no embedding model and worked out of the box. After v1.0, embeddings became mandatory, raising the barrier sharply. Consumer-product developers face two choices: run embeddings on the user&apos;s host, which restricts platforms, or dump the trouble onto the user. After Open-LLM-VTuber introduced mem0, it made it optional, letting people who want to tinker handle it themselves.&lt;/p&gt;
&lt;p&gt;Most of my users use Only-LLM plus skills and enjoy customizing skills and prompts, even when that is often negative optimization. Perhaps only 10% are truly willing to enable mem0.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;What does ADR 0007 bring to these users? They do not write code, and their main scenario is conversation, so they receive none of workspace&apos;s benefits. Instead, memory retrieval changes from an explainable reasoning chain into score ranking: they no longer know why a memory was recalled and lose control over the retrieval process.&lt;/p&gt;
&lt;p&gt;The speed experience is genuinely faster. That is what ADR 0007 brings.&lt;/p&gt;
&lt;h2&gt;How Reversing Item and Category Affects Emotional Companionship and Wiki Links&lt;/h2&gt;
&lt;p&gt;This began here: https://github.com/NevaMind-AI/memU/issues/458&lt;/p&gt;
&lt;p&gt;I opened a feature issue proposing wiki links to connect items across categories and create associative ability.&lt;/p&gt;
&lt;p&gt;My mentor mentioned they were considering reversing category and item. The original event-flow sequence was:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Raw data → LLM extracts atomic items → items enter categories → category summaries are generated from items
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Later, it became:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Raw data → LLM directly updates category documents → items are segmented from category content
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The benefits are:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;It avoids information loss from extracting items first; directly updating categories from raw data is more accurate.&lt;/li&gt;
&lt;li&gt;Items no longer become stale, because they always reflect the latest memory result.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;But the trade-offs may be:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Items become weaker at tracking specific events—what a user did on a particular day—because categories do not keep a ledger of events, so the items segmented from them naturally do not either.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;My mentor asked what I thought as a user of emotional-companion memory.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;After reversing item and category, each category update semantically restructures its items. They become unstable and no longer suit being link anchors. And when categories are overwritten, it becomes difficult to express the contradiction chains, causal chains, and evolution chains mentioned earlier.&lt;/p&gt;
&lt;p&gt;The link role can only fall to resources, but resources are unrefined raw data, with many topics mixed into one conversation. For a resource-to-resource edge, it is unclear which two facts are related, and the cost of judging is high. After the reversal, links have nowhere suitable to attach.&lt;/p&gt;
&lt;p&gt;The benefits certainly exist: information is more complete, and stale memory items almost disappear because items are generated from the latest categories each time. But the cost is that memory retains semantic state while losing contextual links. An agent remembers the fact itself but loses temporal order and causal relations unless it traverses resources.&lt;/p&gt;
&lt;p&gt;For emotional companionship, that cost is substantial. Users care not only that “the agent knows I like cats” (a semantic state), but that “my cat stayed with me through the night I was sick, so I like cats” (a specific event). State-based categories distill events into states, and a shared experience disappears. This does not matter in tool-oriented scenarios, but in companionship scenarios, the events themselves carry the relationship.&lt;/p&gt;
&lt;p&gt;If links must remain after the reversal, I think the better approach is to add an append-only contextual event line based on a timeline. Categories and items manage semantic state and can be overwritten; the event line manages causal and contradiction chains and is only appended to, never rewritten. This event line also makes up for the trade-off that event tracking becomes weaker—they are really the same gap. Relations such as CAUSED and SUPERSEDES are fundamentally relations between events, not between items after the reversal: relations between memories. The cost is maintaining two copies of memory.&lt;/p&gt;
</content:encoded></item><item><title>Blending with the Dust — Starting with Han Li</title><link>https://xnnehang.top/en/posts/heguang-tongchen/</link><guid isPermaLink="true">https://xnnehang.top/en/posts/heguang-tongchen/</guid><description>Starting from a video about blending with the dust, this reflects on Han Li&apos;s Dao heart, character writing in A Record of a Mortal&apos;s Journey to Immortality, and letting go of the self.</description><pubDate>Tue, 30 Jun 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;The Gentleman Is in the Heart&lt;/h2&gt;
&lt;p&gt;&amp;lt;iframe src=&quot;https://player.bilibili.com/player.html?aid=116793918097950&amp;amp;bvid=BV1ZK7N6sEG2&amp;amp;cid=39318850402&amp;amp;page=1&amp;amp;autoplay=0&quot; scrolling=&quot;no&quot; border=&quot;0&quot; frameborder=&quot;no&quot; framespacing=&quot;0&quot; allow=&quot;fullscreen; picture-in-picture&quot; allowfullscreen=&quot;true&quot; style=&quot;height:100%;width:100%; aspect-ratio: 16 / 9;&quot;&amp;gt; &amp;lt;/iframe&amp;gt;&lt;/p&gt;
&lt;p&gt;I found a video on Bilibili with few views, but it moved me deeply.&lt;/p&gt;
&lt;p&gt;Not because it says anything especially profound, but because it uses Han Li as an example and somehow lets me see myself.&lt;/p&gt;
&lt;p&gt;After watching &lt;em&gt;A Record of a Mortal&apos;s Journey to Immortality&lt;/em&gt; for so long, I have always felt comfortable watching Han Li—more comfortable than Tang San, Wang Lin, Xiao Yan, and others. There is a sense of closeness, none of that sharpness. This is also why many people think of him as “mortal.”&lt;/p&gt;
&lt;p&gt;Qin Mu is the complete opposite of Han Li. Qin Mu&apos;s cleverness and intricate mind are displayed openly. Whatever he thinks, he says; he never holds it in. He also has an extremely open-source spirit, never reluctant to give away what he has thought of. When I first read &lt;em&gt;Tales of Herding Gods&lt;/em&gt;, I thought Qin Mu was much like me, but he always also carried a sense of immaturity.&lt;/p&gt;
&lt;p&gt;Han Li&apos;s intelligence, by contrast, is almost always hidden beneath the iceberg. Others never see even one tenth of his true thoughts. More often he simply acts silently and does not explain himself. Of course, the video&apos;s account of “blunting his sharpness” says it better than I can.&lt;/p&gt;
&lt;p&gt;The video explained why I could not articulate my preference for Han Li, and likewise why I could not articulate my dislike for Tang San.&lt;/p&gt;
&lt;p&gt;Then it showed me that the signs in Han Li&apos;s ideas and actions conform to “blending with the dust.” He is a true gentleman.&lt;/p&gt;
&lt;p&gt;A gentleman is not something forced into shape. Take Chen Changsheng: he has read the Three Thousand Daoist Canons and can name more than ten ways to write a gentleman. His heart is astonishingly pure; he could be called greatly good, perhaps even a sage if great merit and virtue were added.&lt;/p&gt;
&lt;p&gt;But from Chen Changsheng&apos;s first appearance in animation, he has felt artificial to me. The production team cares too much about the scholar&apos;s image of warm jade and pushes it too far. It turns Chen Changsheng into an outward gentleman—or, more accurately, someone with a respectable facade. By neglecting the character&apos;s depth, they make him too thin. It is hard not to feel uncomfortable and suspect that something unknown is hidden deeper down.&lt;/p&gt;
&lt;p&gt;On the &lt;em&gt;Mortal&apos;s Journey&lt;/em&gt; side, however, the production team places Han Li&apos;s inner complexity, choices, and psychological dilemmas in plain sight. Their presentation makes viewers feel they have seen Han Li whole, rather than only a shell.&lt;/p&gt;
&lt;p&gt;A gentleman is not in speech or manners. A gentleman is in the heart.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;About the Video&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;Written by Claude Opus 4.6.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The video breaks Han Li&apos;s conduct into four steps: blunt his sharpness, untangle his complications, soften his light, and blend with the dust. Honestly, I usually skip this kind of “several steps” theory because it feels like padding out a structure. But after watching this one, I did think about it for a long time.&lt;/p&gt;
&lt;p&gt;The first step is concealing one&apos;s strengths. Han Li&apos;s cleverest trait is that he never lets others think he is clever—when that sentence appeared, I felt it had struck exactly the point. The cultivation world cannot accommodate people who are too clear-sighted. The moment you show insight higher than others&apos;, people will not admire you; they will guard against you. No one likes being seen through.&lt;/p&gt;
&lt;p&gt;When Yellow Maple Valley abandoned him as a disposable pawn, he did not question it or grow angry. He silently fled to the Scattered Star Seas. I probably could not do that. When people abandon me, I may not say anything, but I will repeatedly think, “Why?” Han Li would not. He makes himself into an obtuse angle: if you do not pierce others, they will not regard you as a threat.&lt;/p&gt;
&lt;p&gt;Then comes seeing through things without saying so. The video speaks of four states of mind: treating oneself as another, another as oneself, another as another, and oneself as oneself. I can understand the first three; the last is the hardest. Do not care about other people&apos;s evaluations; hear your own voice first.&lt;/p&gt;
&lt;p&gt;Honestly, I have not done it. Too many things matter to me: other people&apos;s views, their expectations, even what they think of these blog posts. Sometimes I revise wording again and again before publishing, until in the end I have forgotten what I wanted to say. I suppose this is why I return to &lt;em&gt;Mortal&apos;s Journey&lt;/em&gt; every so often—not for the fights, but to watch how Han Li handles these relationships. To remind myself that there is a fourth option.&lt;/p&gt;
&lt;p&gt;The third step is letting others shine. The video uses Lin Xiangru as an example: Lin lets Lian Po understand that his light belongs on the battlefield. Han Li does much the same. He lets the old monsters of Tiannan fight for fame and gain while he quietly takes the actual benefits. This is neither pleasing people nor flattering them; it is genuinely seeing another person&apos;s value and helping it flourish.&lt;/p&gt;
&lt;p&gt;I am less moved by this part than the first two. Perhaps my life has not yet reached the stage where I need to “let others shine.” I am still at the stage of “first, do not let myself go out.”&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;Blending with the Dust&lt;/h2&gt;
&lt;p&gt;The last step, blending with the dust, feels like such an elevated phrase.&lt;/p&gt;
&lt;p&gt;It means letting go of discriminating thoughts and prejudices of high and low, noble and base. The video has a line that made me laugh: “People who listen to classical music look down on people who listen to pop; people who watch stage plays look down on people who watch errenzhuan.” But after laughing, it did not feel quite right, because I have this discriminating mind too. I used to look down on mindless power fantasies and think only works like &lt;em&gt;Mortal&apos;s Journey&lt;/em&gt; counted as good. Later I thought: they enjoy what they watch, and I enjoy what I watch; as long as we do not interfere with each other, that is fine.&lt;/p&gt;
&lt;p&gt;And &lt;strong&gt;old-man energy&lt;/strong&gt; arises when you believe your own tastes are superior and cannot resist judging, blaming, and correcting others. So people do not become old-manish because they get old; they get old-manish because they are old-manish (bushi).&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;a href=&quot;https://www.bilibili.com/video/BV1vXQgBEEPX&quot;&gt;What does the “happiness” we keep talking about actually mean? | Yi Mai San Lian EP17&lt;/a&gt; discusses that old-man feeling at about 5:50.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Han Li does not have this discriminating mind. From the Seven Mysteries Sect to Yellow Maple Valley, from the Scattered Star Seas to Tiannan, his status changes again and again, but he never looks down on the old Foundation Establishment friends because he has become a Nascent Soul cultivator. What he respects is not status, but the light and warmth each person gives off while absorbed in what they love.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/img/heguang-tongchen/wenxi-178.png&quot; alt=&quot;Episode 178: the dialogue scenes are still astonishing.&quot; /&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Episode 178: the dialogue scenes are still astonishing.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The video quotes &lt;em&gt;Soul&lt;/em&gt;: every soul needs a spark when it comes into the world, and that spark is a passion.&lt;/p&gt;
&lt;p&gt;I wrote before in [[On Mortal Lives in Renegade Immortal and A Record of a Mortal&apos;s Journey to Immortality]] that the essence of living as a mortal is setting aside a cultivator&apos;s identity and experiencing life as an ordinary person again. Looking at it now, Han Li&apos;s “blending with the dust” means something similar. Whatever realm he cultivates to, in a corner of his heart Han Li still considers himself a mortal—or rather, preserves that corner of humanity and the feeling of being alive. Wang Lin&apos;s mortal life is a pot of fruit wine, festivals across the four seasons, and the lived warmth of the blacksmith&apos;s family. Han Li&apos;s is subtler. He does not need to deliberately live as a mortal, or deliberately try to fit in, because he has always been this way.&lt;/p&gt;
&lt;p&gt;Seen this way, Han Li&apos;s Dao heart is far steadier than Wang Lin&apos;s. Wang Lin found his Dao amid AABB and BBAA (I am really not trying to hate on him). Han Li knew what he wanted from the beginning and only continued to make it firm. His cultivation is pure, like someone with a pure desire for knowledge who learns in order to seek knowledge and discern truth. Han Li&apos;s cultivation and Dao heart are just as pure. (Perhaps at first they were mixed with a wish to catch up to his wife, but later he even forgot to look for her, did he not?) Wang Lin&apos;s cultivation began with revenge, and later with reviving Li Muwan. He never understood why he cultivated in the first place; he was only a puppet passively pulled forward by hatred and romance. Can such a Dao heart truly be pure?&lt;/p&gt;
&lt;p&gt;Han Li was plotted against by Doctor Mo, abandoned by Yellow Maple Valley, adrift in the Scattered Star Seas, entered and left Devilfall Valley, and fell into a spatial rift. These experiences would make anyone extreme or cold, but Han Li remains gentle and unhurried, neither servile nor arrogant. Call him gentle, call him calculating—either way, he has none of that viciousness. Wang Lin, from the time Teng Huayuan destroyed his entire clan, stepped onto a path wrapped in violence. He fought the Teng clan, then later fought the Heavenly Dao. He has never stopped since, and I cannot see a trace of living humanity in him. I see only, “Noisy! Die!” It is genuinely abstract. I am not criticizing him just to criticize him; in a sense, he has truly lost empathy. Perhaps this is also because the &lt;em&gt;Renegade Immortal&lt;/em&gt; animation only keeps shaping standard, stereotyped villains, so every ruthless move Wang Lin makes is hard to fault.&lt;/p&gt;
&lt;p&gt;But are villains really all the sort who walk up, provoke someone with “You little Core Formation brat,” and then stretch out their necks for the protagonist to kill? Meng Tuzi is the most laughable villain I have seen.&lt;/p&gt;
&lt;p&gt;In &lt;em&gt;Mortal&apos;s Journey&lt;/em&gt;, viewers see Xuan Gu fall and call for an entire Xuan Gu side story. When Young Lord Wen dies, they cry, “No, Young Lord!” Perhaps viewers are letting their facial features guide their values? But Xuan Gu&apos;s ultimate personal charm as an antagonist cannot be denied.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/img/heguang-tongchen/xuangu-yuluo.png&quot; alt=&quot;Xuan Gu falls&quot; /&gt;&lt;/p&gt;
&lt;p&gt;What is more remarkable is that every character in &lt;em&gt;Mortal&apos;s Journey&lt;/em&gt; is complex and many-sided. Even when they stand against the protagonist and receive the villain label, they are not simply divided into good and evil. Or rather, &lt;em&gt;Mortal&apos;s Journey&lt;/em&gt; tries hard to avoid praising good and punishing evil, and to avoid manufacturing opposition. There are many satirical novels that advertise “demonic cultivators act human while righteous cultivators do not,” then all reach the same conclusion: demonic cultivators are not necessarily evil; look at what they actually do. &lt;em&gt;Mortal&apos;s Journey&lt;/em&gt; is more direct. It creates many such characters: from their own perspective, perhaps they can only do what they do. For instance, Wen Qiang is right to protect his daughter, and right to seek revenge against the decayed management of the Star Palace.&lt;/p&gt;
&lt;p&gt;But he is also genuinely a villain, and that is what makes such a character compelling.&lt;/p&gt;
&lt;p&gt;His daughter Wen Siyue, along with later Gongsun Xing and Mei Ning, also establishes the many sides and standpoint of Old Devil Han to some degree.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/img/heguang-tongchen/wensiyue-1.png&quot; alt=&quot;Wen Siyue&quot; /&gt;
&lt;img src=&quot;../../assets/img/heguang-tongchen/wensiyue-2.png&quot; alt=&quot;Wen Siyue&quot; /&gt;
&lt;img src=&quot;../../assets/img/heguang-tongchen/wensiyue-3.png&quot; alt=&quot;Wen Siyue&quot; /&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The wordless dramatic scene in episode 106.&amp;lt;br&amp;gt;
Two kneelings nearly a hundred years apart: the second is a test. Wen Siyue learns that Han Li is the senior who had inexplicably helped her a century earlier; Han Li knows that she knows, but neither says it. And after this parting, the day they meet again is far away.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;A fairly complete compilation is available here: &lt;a href=&quot;https://www.bilibili.com/video/BV16vTA6hE2m&quot;&gt;In &lt;em&gt;A Record of a Mortal&apos;s Journey to Immortality&lt;/em&gt;, Siyue&apos;s kneeling recognized him as Senior Han&lt;/a&gt;. Han Li used a disguise technique, so Wen Siyue saw an old man; he even deliberately copied an old man&apos;s voice and tone.&lt;/p&gt;
&lt;p&gt;Yet the single line &lt;code&gt;Do not mention this to anyone else&lt;/code&gt; immediately makes Wen Siyue connect him with Senior Han, who had helped her multiple times for no apparent reason.&lt;/p&gt;
&lt;p&gt;&amp;lt;iframe src=&quot;https://player.bilibili.com/player.html?bvid=BV16vTA6hE2m&amp;amp;page=1&amp;amp;autoplay=0&quot; scrolling=&quot;no&quot; border=&quot;0&quot; frameborder=&quot;no&quot; framespacing=&quot;0&quot; allow=&quot;fullscreen; picture-in-picture&quot; allowfullscreen=&quot;true&quot; style=&quot;height:100%;width:100%; aspect-ratio: 16 / 9;&quot;&amp;gt; &amp;lt;/iframe&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.bilibili.com/video/BV1JpWwzUEmx/&quot;&gt;A Record of a Mortal&apos;s Journey to Immortality: an analysis of Wen Siyue&apos;s story line&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;There is also a full analysis of the story line here.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/img/heguang-tongchen/gongsunxing-yangguo.png&quot; alt=&quot;Gongsun Xing&quot; /&gt;
&lt;img src=&quot;../../assets/img/heguang-tongchen/gongsunxing-2.png&quot; alt=&quot;Gongsun Xing&quot; /&gt;
&lt;img src=&quot;../../assets/img/heguang-tongchen/gongsunxing-3.png&quot; alt=&quot;Gongsun Xing&quot; /&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;One glimpse of Yang Guo, a lifetime led astray. This was mentioned in the scrolling comments, and it is true: this scene resembles the moment Guo Xiang sees the Divine Condor Hero remove his mask. More coincidentally, this outfit makes Han Li look most like Louis Koo, Yang Guo&apos;s actor.&amp;lt;br&amp;gt;
Gongsun Xing is the cutest character I have ever seen—several degrees cuter than Silvermoon.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Han Li sees his own guilt and feeling toward his parents in Gongsun Xing, then gives her all his resources below Core Formation. This indirectly leaves him without a suitable magical tool when he later pretends to be a low-level disciple in the Luoyun Sect. Before the competition, he spends days drawing talismans.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/img/heguang-tongchen/meining-1.png&quot; alt=&quot;Mei Ning&quot; /&gt;
&lt;img src=&quot;../../assets/img/heguang-tongchen/meining-2.png&quot; alt=&quot;Mei Ning&quot; /&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;What a pity for Mei Ning. What a pity.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;If Mei Ning had shown even a trace of determination instead of uncertainty, Han Li would have given everything to her without reservation. Old Devil Han says that forming a Nascent Soul will take one or several centuries, an endlessly distant future—would that not frighten a young girl? Then, in a few decades, he becomes a grand elder. Mei Ning&apos;s temperament is relatively weak; if Mo Caihuan or Senior Sister Chen had been there, they would have firmly chosen to follow Han Li. Yet it is precisely that indecision and vulnerability, born of having been protected too well by her brother, combined with her pitiable expression, that leaves many fellow Daoists and me unable to let go. Still, following Zi Ling is not bad. Zi Ling is a professional at raising children; she previously raised Wen Siyue well.&lt;/p&gt;
&lt;p&gt;And the production team has truly put thought into it. They even bring in &lt;em&gt;A New Account of the Tales of the World&lt;/em&gt;. Very few people can understand that layer of symbolism; I certainly cannot.&lt;/p&gt;
&lt;p&gt;Perhaps anime like this is exhausting to make and hard to please everyone with; it is also exhausting to watch. Dialogue scenes demand thought and feeling, and sometimes cannot be understood without an explanation. But as I grow older, I find it hard to say I can simply leave my brain aside when watching animation, so I can gradually watch only this sort of animation.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;I seem to have wandered into many unrelated things, because I cannot specifically say what I felt about Han Li when I watched those scenes. But I vaguely feel that scenes like these are exactly what make “blending with the dust” seem like a phrase invented for Han Li. He is the phrase itself.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;Letting Go of the Self&lt;/h2&gt;
&lt;p&gt;At the end, the video summarizes: blunting one&apos;s sharpness removes the competitive self; untangling complications releases the self-centered perspective in order to understand others; softening one&apos;s light releases jealousy in order to help others achieve; blending with the dust releases the arrogant self in order to embrace all beings. It is a continual process of “letting go of the self.”&lt;/p&gt;
&lt;p&gt;Letting go of the self. Those two words carry weight.&lt;/p&gt;
&lt;p&gt;I still cannot do it. I care about too much. Whether I am writing code or a blog post, I am always thinking about what other people will see. Sometimes an idea is good, but I swallow it because I fear people will find it childish. Han Li would not do that. He understands everything in his heart—who is plotting and who is sincere—but leaves three parts unspoken when words reach his lips. Not because he dares not speak, but because there is no need to.&lt;/p&gt;
&lt;p&gt;To blend with the dust is not to make oneself dim, but to change from a body that emits light into light itself.&lt;/p&gt;
&lt;p&gt;Perhaps that is the best state after one has truly seen the world.&lt;/p&gt;
&lt;p&gt;Still, I am far from having seen the world. Let me finish this post first.&lt;/p&gt;
</content:encoded></item><item><title>What Is memU? Let&apos;s Break It Down (An Ongoing Series)</title><link>https://xnnehang.top/en/posts/memu-source-code-breakdown/</link><guid isPermaLink="true">https://xnnehang.top/en/posts/memu-source-code-breakdown/</guid><description>A breakdown of memU focused on its main paths and ADR architecture documents, currently following through ADR 0008.</description><pubDate>Mon, 29 Jun 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;img src=&quot;../../assets/img/memu-source-code-breakdown/cover.jpeg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;[!NOTE]
&lt;strong&gt;AI collaboration disclosure:&lt;/strong&gt; This post was written jointly by Xnne and &lt;a href=&quot;https://github.com/xnne-bot&quot;&gt;Korewaxnne&lt;/a&gt; (a cyber cat). Xnne is responsible for the direction and technical analysis; Korewaxnne helped organize the structure, polish the language, and format it.&amp;lt;br&amp;gt;
This post will also be updated over the long term.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I had actually broken down memU once before.&lt;/p&gt;
&lt;p&gt;But it was in the middle of an architectural iteration, and I had no reading guide for ADR 0007. So I deleted that earlier breakdown entirely. This invisibly makes the article harder to read, though I will try to keep it simple.&lt;/p&gt;
&lt;h2&gt;Changes to the memorize / retrieve pipeline&lt;/h2&gt;
&lt;p&gt;Previously, &lt;code&gt;memorize&lt;/code&gt; was a standalone Python script, and &lt;code&gt;retrieve&lt;/code&gt; was another standalone Python script.&lt;/p&gt;
&lt;p&gt;Previously, the objects handled by memorize and retrieve were a &lt;code&gt;single file (Chat)&lt;/code&gt; plus a &lt;code&gt;Skill&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Previously, retrieval used &lt;code&gt;LLM retrieve&lt;/code&gt; plus &lt;code&gt;RAG retrieve&lt;/code&gt;, distinguished by mode, and only one route ran at a time.&lt;/p&gt;
&lt;p&gt;After &lt;a href=&quot;https://github.com/NevaMind-AI/memU/pull/466&quot;&gt;#466&lt;/a&gt;:&lt;/p&gt;
&lt;h3&gt;memorize&lt;/h3&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/img/memu-source-code-breakdown/memorize-pipeline-1.png&quot; alt=&quot;&quot; /&gt;
&lt;img src=&quot;../../assets/img/memu-source-code-breakdown/memorize-pipeline-2.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Memorize became two scripts: &lt;code&gt;memorize.py&lt;/code&gt; plus &lt;code&gt;memorize_workspace.py&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The objects handled by memorize and retrieve gained a &lt;code&gt;workspace&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Simply put, memorize used to work on a collection of conversations, like mem0:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;{
  &quot;user&quot;: &quot;hi&quot;,
  &quot;assistant&quot;: &quot;hi,how can I help you today?&quot;,
  ...
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;More precisely, it was a single file. It could also be a long string, but it did not contain complex nested hierarchy.&lt;/p&gt;
&lt;p&gt;A workspace is a folder. It can be a complex folder, such as a project directory.&lt;/p&gt;
&lt;p&gt;I will discuss workspace retrieval later.&lt;/p&gt;
&lt;h3&gt;retrieve&lt;/h3&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/img/memu-source-code-breakdown/retrieve-pipeline.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;ADR 0007 says retrieve should implement BM25 plus hybrid search. But that method is not implemented yet; &lt;code&gt;retrieve-workspace&lt;/code&gt; is still only a simple &lt;code&gt;top-k&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;I do not know whether my earlier conversation with my mentor in [[memU&apos;s Architectural Shift Through the Eyes of a Consumer-Facing Developer]] had an effect. It seems the mentor convinced the leader to retain both LLM retrieve and RAG retrieve. In &lt;a href=&quot;https://github.com/NevaMind-AI/memU/pull/467&quot;&gt;#467&lt;/a&gt;, both were added to the CLI:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;memu memorize notes/meeting.md
memu memorize-workspace ./workspace
memu retrieve &quot;What are this user&apos;s launch preferences?&quot;
memu retrieve-workspace &quot;deploy checklist&quot;
memu export
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here, retrieve is the older path where either &lt;code&gt;RAG&lt;/code&gt; or &lt;code&gt;LLM&lt;/code&gt; was enabled in configuration.&lt;/p&gt;
&lt;p&gt;Workspace was also implemented separately.&lt;/p&gt;
&lt;p&gt;There is still a little architectural redundancy. Should retrieve retain &lt;code&gt;RAG mode&lt;/code&gt;? In principle, it should, but once retained, it resembles &lt;code&gt;retrieve-workspace&lt;/code&gt; in principle while doing different work.&lt;/p&gt;
&lt;p&gt;But if it is removed in favor of reusing workspace, their meanings differ. In short, people who are sensitive to architectural asymmetry may find this uncomfortable. The most comfortable architecture would use workspace to replace &lt;code&gt;RAG/LLM retrieve&lt;/code&gt; entirely, but trade-offs are necessary.&lt;/p&gt;
&lt;p&gt;For me, though, it&apos;s okay. At least we fought for &lt;code&gt;LLM retrieve&lt;/code&gt; to remain. And it does seem to be staying—hopefully it is not merely being removed through separate PRs =-=.&lt;/p&gt;
&lt;h2&gt;Data Model Changes&lt;/h2&gt;
&lt;h3&gt;old memorize&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;Resource ──1:N──▶ RecallEntry ──N:M──▶ RecallFile
                                  (through RecallFileEntry)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;One Resource (the original file) produces multiple RecallEntries (items extracted by the LLM). Entries connect through RecallFileEntry to RecallFiles, which are topical documents such as “Profile” or “Goals.”&lt;/p&gt;
&lt;h3&gt;latest memorize (adding the workspace pipeline)&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;Resource ──N:M──▶ RecallFile ──1:N──▶ RecallFileSegment
              (through RecallFileResource)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The workspace route skips RecallEntry. A Resource connects directly to a RecallFile through RecallFileResource. Each RecallFile is then split into multiple RecallFileSegments for retrieval.&lt;/p&gt;
&lt;h3&gt;Data Model&lt;/h3&gt;
&lt;p&gt;&amp;lt;div class=&quot;img-center&quot; style=&quot;max-width: 24rem; margin: 0 auto;&quot;&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/img/memu-source-code-breakdown/data-model.png&quot; alt=&quot;Data model&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/div&amp;gt;&lt;/p&gt;
&lt;h3&gt;What&apos;s new?&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;RecallFileSegment&lt;/code&gt;&lt;/strong&gt; is the most important addition. A RecallFile is split into one to N segments, and every segment has its own text and embedding. Retrieval searches segments, then rolls the hit up to the owning file. Segmentation differs by track:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;skill: one segment for the entire skill (&lt;code&gt;name: ...\ndescription: ...&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;memory: split by line, skipping blank lines and Markdown headings&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;RecallFileResource&lt;/code&gt;&lt;/strong&gt; is the many-to-many relation table from Resource to RecallFile: provenance. It records which source files were synthesized into a file&apos;s content. The old path linked indirectly through Entry; the new path needs this direct link.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;Resource.track&lt;/code&gt;&lt;/strong&gt; is a new field that identifies the source: &lt;code&gt;&quot;chat&quot;&lt;/code&gt; / &lt;code&gt;&quot;skill&quot;&lt;/code&gt; / &lt;code&gt;&quot;workspace&quot;&lt;/code&gt;. Resources in the old path are &lt;code&gt;None&lt;/code&gt;. Workspace retrieval uses &lt;code&gt;track=&quot;workspace&quot;&lt;/code&gt; to search only Resources originating from a workspace.&lt;/p&gt;
&lt;h3&gt;What is track?&lt;/h3&gt;
&lt;p&gt;The term track appears three times in the data model—Resource, RecallFile, and RecallFileSegment—but it has &lt;strong&gt;two layers of meaning&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;First layer: Resource.track — “Where did this source file come from?”&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;memorize_workspace&lt;/code&gt; classifies it automatically from the directory name:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Top-level directory&lt;/th&gt;
&lt;th&gt;Resource.track&lt;/th&gt;
&lt;th&gt;Meaning&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;chat/&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;&quot;chat&quot;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Conversation records&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;agent/&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;&quot;skill&quot;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Agent execution logs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Other&lt;/td&gt;
&lt;td&gt;&lt;code&gt;&quot;workspace&quot;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Ordinary project files&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;(old memorize)&lt;/td&gt;
&lt;td&gt;&lt;code&gt;None&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;A single-file path with no track concept&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;Second layer: RecallFile.track / RecallFileSegment.track — “What kind of document is this?”&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;There are only two values: &lt;code&gt;&quot;memory&quot;&lt;/code&gt; for a topical memory document and &lt;code&gt;&quot;skill&quot;&lt;/code&gt; for a skill document.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The mapping between the layers:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Resource.track    →    RecallFile.track
─────────────────────────────────────────
&quot;chat&quot;            →    &quot;memory&quot;
&quot;skill&quot;           →    &quot;skill&quot;
&quot;workspace&quot;       →    ❌ Does not generate a RecallFile
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Workspace-track files store only Resources, with captions and embeddings, for &lt;code&gt;INDEX.md&lt;/code&gt; retrieval. They do not synthesize documents or split segments.&lt;/p&gt;
&lt;p&gt;RecallFileSegment.track is redundantly copied from the owning RecallFile, so retrieval can filter by track without a join.&lt;/p&gt;
&lt;p&gt;:::note
It appears track will later be removed, with chat, workspace, and skill stored in separate database-table structures. That would be cleaner.
:::&lt;/p&gt;
&lt;h3&gt;What is entry?&lt;/h3&gt;
&lt;p&gt;Entry (&lt;code&gt;RecallEntry&lt;/code&gt;) is the core intermediate layer of the old memorize path: an &lt;strong&gt;atomic fact&lt;/strong&gt; extracted by the LLM from source content.&lt;/p&gt;
&lt;p&gt;For example, from a conversation:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;User: I am going to Tokyo on business next week. Help me book a flight for Monday.
Assistant: Okay, I have booked you a Monday flight to Tokyo.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The LLM extracts multiple entries:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;memory_type&lt;/th&gt;
&lt;th&gt;summary&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;event&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The user will travel to Tokyo on business next Monday.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;behavior&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The user prefers the AI to book flights directly without confirmation.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;profile&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The user travels for business and may be a professional.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;There are six &lt;code&gt;memory_type&lt;/code&gt;s: &lt;code&gt;profile&lt;/code&gt;, &lt;code&gt;event&lt;/code&gt;, &lt;code&gt;knowledge&lt;/code&gt;, &lt;code&gt;behavior&lt;/code&gt;, &lt;code&gt;skill&lt;/code&gt;, and &lt;code&gt;tool&lt;/code&gt;. Each type has its own extraction prompt. The LLM runs once per type and extracts the entries belonging to it.&lt;/p&gt;
&lt;p&gt;The extracted entries are embedded, then assigned through RecallFileEntry to the corresponding RecallFile, a topical document. Multiple entries are gathered into one file, whose content becomes a synthesized summary of those entries.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Why does the workspace route skip entries?&lt;/strong&gt; Workspace source files—code, documents, configuration—are not conversations and do not suit extracting atomic facts by memory type. The workspace route instead has the LLM route and synthesize source content directly into RecallFiles, removing the intermediate entry layer.&lt;/p&gt;
&lt;h2&gt;The Correspondence of the Three Memory Layers&lt;/h2&gt;
&lt;h3&gt;Data-model mapping&lt;/h3&gt;
&lt;p&gt;We all know the three-layer memory relationship: &lt;strong&gt;Resource → Category → Memory Item&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Mapped to the data model:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Resource     = Resource        (raw material: one file or one conversation)
Category     = RecallFile      (a topical document such as &quot;Profile&quot; or &quot;Goals&quot;)
Memory Item  = depends on the route ↓
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The Memory Item differs between the routes:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Old memorize route&lt;/th&gt;
&lt;th&gt;New workspace route&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Memory Item&lt;/td&gt;
&lt;td&gt;&lt;code&gt;RecallEntry&lt;/code&gt; (an atomic fact extracted by the LLM)&lt;/td&gt;
&lt;td&gt;&lt;code&gt;RecallFileSegment&lt;/code&gt; (a slice of a document)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;:::note
ADR 0007 calls these three layers L0 / L1 / L2: L0 is Resource, L1 is Category, and L2 is Memory Item. The meaning is the same; only the numbering changes.
:::&lt;/p&gt;
&lt;h3&gt;The execution order of the two routes is reversed&lt;/h3&gt;
&lt;p&gt;The old route has a &lt;strong&gt;counterintuitive feature&lt;/strong&gt;: the pipeline produces a Memory Item—an Entry—before synthesizing a Category—File. It goes from fine to coarse:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Old-path execution order: Resource → Entry (fine) → File (coarse)
&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;Q: I wonder whether this synthesis from old-path Entry to Category is direct concatenation, or whether it calls an LLM again.&amp;lt;br&amp;gt;
A: It is not direct concatenation. It calls an LLM again.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The new route reverses this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;New-path execution order: Resource → File (coarse) → Segment (fine)
&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;Q: I wonder whether the reversed path affects fine-grained extraction. Does combining information organization and extraction weaken its ability to extract information?&amp;lt;br&amp;gt;
A: It does reduce that ability. The former path performed independent entry extraction for every memory type—effectively N separate runs—then called again to synthesize.&amp;lt;br&amp;gt;
&lt;strong&gt;But this is not necessarily a regression&lt;/strong&gt;, because:&amp;lt;br&amp;gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Workspace source files—code, documentation, configuration—do not suit “extracting atomic facts” the way conversations do. How would you extract standalone memory items from a Python file? Synthesizing a summary document first and then splitting it is more reasonable.&amp;lt;br&amp;gt;&lt;/li&gt;
&lt;li&gt;Workspace retrieval has &lt;strong&gt;segment → file roll-up&lt;/strong&gt;. Even if a single-line hit is imprecise, once it rolls up to the right file, the user receives the complete document and loses no information.&amp;lt;br&amp;gt;&lt;/li&gt;
&lt;li&gt;Retrieval through old-path entries is precise, but entries are isolated. Receiving &lt;code&gt;&quot;The user likes black coffee&quot;&lt;/code&gt; provides no context. After rolling up to a file, the new route has the complete topical document.&amp;lt;br&amp;gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;
&lt;h3&gt;The question of direction: why is workspace unsuited to “divide, then synthesize”?&lt;/h3&gt;
&lt;p&gt;But the key point seems to be this:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The coupling direction of information organization and information retrieval is reversed.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;In endless chat memory, you need only catch a few relevant fragments, then reverse-retrieve the resource to obtain all related information. The information is complete and independent. A divide-then-synthesize method suits it.&lt;/p&gt;
&lt;p&gt;But in a workspace, a fragments-to-resource approach does not work as well. What fragments can recall are code fragments. If you retrieve a Data Model, you still need another search to learn where that Data Model is used; it does not recall all related information. Instead, it retrieves a lot of garbage—many definitions with no relation to their use sites or architecture.&lt;/p&gt;
&lt;p&gt;What we need is a high-level document readable by both agents and humans, and then fragments cut from that document.&lt;/p&gt;
&lt;p&gt;So workspace as a whole suits a synthesize-then-divide form. That is the new route.&lt;/p&gt;
&lt;p&gt;Precisely because of this difference, I think the chat and workspace paths should intentionally stay distinct.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;If chat later becomes synthesize-then-divide too,&lt;/p&gt;
&lt;p&gt;I could still accept it, but there would be some information loss in exchange for a major speed increase and lower token consumption. That depends on the trade-off, though I truly like LLM mode.&lt;/p&gt;
&lt;h2&gt;What&apos;s different in ADR 0008&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/NevaMind-AI/memU/commit/ff90dac6976bc920667e03d295a75d5da8626f75&quot;&gt;ADR 0008&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;Input-source change: a change in the focus of attention&lt;/h3&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/img/memu-source-code-breakdown/memorize-pipeline-1.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;In ADR 0007, we saw this diagram. It required &lt;code&gt;chat/&lt;/code&gt;, &lt;code&gt;skill/&lt;/code&gt;, and &lt;code&gt;workspace/&lt;/code&gt; (everything else) as three sources, each taking a different route.&lt;/p&gt;
&lt;p&gt;But it had an uncomfortable design problem: where do those three folders come from? Or, while a conversation is happening, do they change often? Skill is likely stable most of the time. A workspace may be an entire project workspace, and for a hundred-thousand-line project, modifying twenty or thirty lines at a time is insignificant against the whole project.&lt;/p&gt;
&lt;p&gt;That makes the model dull to contextual change. Or more exactly, the three sources are unreliable to some degree: they inevitably make the model keep attending to unimportant things, without a good way to constrain it.&lt;/p&gt;
&lt;p&gt;After ADR 0008, &lt;strong&gt;the input source returned once more to conversations with an agent and tool-call records, as the only raw input.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;But the core of 0007 was not discarded. It uses an LLM to extract the input conversation data into different pieces to be processed:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;memory&lt;/code&gt;, &lt;code&gt;project&lt;/code&gt;, and &lt;code&gt;skill&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;From large files to an embedding index&lt;/h3&gt;
&lt;p&gt;The three large files defined earlier—&lt;code&gt;MEMORY.md&lt;/code&gt;, &lt;code&gt;INDEX.md&lt;/code&gt;, and &lt;code&gt;SKILL.md&lt;/code&gt;—were split into folders of L1 child files plus &lt;s&gt;L2 index files&lt;/s&gt;. This avoids handling a large amount of content whenever a large file is rebuilt.&lt;/p&gt;
&lt;p&gt;The index itself is not stored on disk as a file. It is an embedding index, which is interesting. I wonder whether it simply stores L1 embeddings, or what exactly it does.&lt;/p&gt;
&lt;p&gt;Claude says it does not merely turn L1 files into embeddings. It slices L1, creates embeddings, and attaches metadata such as the source file and line number.&lt;/p&gt;
&lt;p&gt;That is indeed a very good approach.&lt;/p&gt;
&lt;p&gt;Later, it only needs to modify the appropriate child file and update the index. The troublesome part of embeddings is deletion: metadata line numbers change, and when an entry in a child file is deleted, how should L2 automatically notice, delete its corresponding embedding, and update every entry?&lt;/p&gt;
&lt;p&gt;It sounds troublesome, but it is only an engineering-control problem. And it can be avoided: large language models do not need exact line numbers; they can grep to locate content. The best approach is not to constrain line numbers, avoiding full metadata updates in the database.&lt;/p&gt;
&lt;p&gt;Though perhaps there were never line references in the first place; Claude only used them as an example.&lt;/p&gt;
&lt;h3&gt;CLI simplification&lt;/h3&gt;
&lt;p&gt;The originally defined &lt;code&gt;memorize-workspace&lt;/code&gt; and &lt;code&gt;retrieve-workspace&lt;/code&gt; were removed.&lt;/p&gt;
&lt;p&gt;What I care about is whether hybrid search now directly replaces the old &lt;code&gt;old-retrieve&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;And I need to confirm whether every &lt;code&gt;on_turn&lt;/code&gt; memorize step first calls an operation that semantically separates a conversation into three tracks. That consumption is not small, though it is invisible when asynchronous.&lt;/p&gt;
&lt;h3&gt;The trade-off in on_turn frequency&lt;/h3&gt;
&lt;p&gt;After discussing it with Claude, since &lt;code&gt;retrieve-workspace&lt;/code&gt; has been removed, hybrid search must fall onto the former &lt;code&gt;retrieve&lt;/code&gt; design. In other words, &lt;code&gt;old-retrieve&lt;/code&gt; will be directly replaced because it is too heavy.&lt;/p&gt;
&lt;p&gt;That is indeed a more comfortable architecture, because when workspace and chat were initially separated, some part of the architecture always felt wrong to me.&lt;/p&gt;
&lt;p&gt;But whether the three-way separation happens every conversational turn or is submitted in accumulated batches is still under discussion. It affects whether the process is too heavy, and directly changes how many turns occur before memU runs. mem0 runs once every conversation turn; for memU, splitting memories every several rounds changes its runtime frequency. Users could configure it. If I designed it, I would do that.&lt;/p&gt;
&lt;p&gt;And following this design philosophy, I cannot imagine what it would do without splitting into three paths first.&lt;/p&gt;
&lt;p&gt;Also, if it splits into three paths every turn, does it need at least four LLM calls?&lt;/p&gt;
&lt;p&gt;Claude says yes. It is not light. According to Claude&apos;s analysis, old memorize generally did not run every turn; it would manually process an entire long conversation in a batch. ADR 0008&apos;s on_turn design hopes to trigger automatically, but frequency becomes the problem. If it runs every turn, users may find that their memory files consume more tokens than their conversations.&lt;/p&gt;
&lt;p&gt;I suddenly thought that a lightweight LLM call could decide whether enough messages have accumulated since the last memorize. That would avoid fixing the number of rounds while still triggering automatically.&lt;/p&gt;
&lt;p&gt;Claude added that token count could decide whether to memorize.&lt;/p&gt;
&lt;h2&gt;What&apos;s new in ADR 0009 and 00010?&lt;/h2&gt;
&lt;p&gt;Although I have not followed the ADRs recently, I have actually already been working on them.&lt;/p&gt;
&lt;p&gt;Most of my work over the last few days has been:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Aligning memU commit&apos;s embedding return contract: &lt;a href=&quot;https://github.com/NevaMind-AI/memU/pull/504&quot;&gt;#504&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Removing environment, turn, and repeatedly injected &lt;code&gt;AGENTS.md&lt;/code&gt; information from Codex classification to avoid token waste and extracting memories from irrelevant content: &lt;a href=&quot;https://github.com/NevaMind-AI/memU/pull/511&quot;&gt;#511&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Adding a fast agentic-install workflow for the latest HEAD: inheriting old configuration, checking for new configuration, and inheriting the memory database. It is very convenient, especially in OpenClaw: &lt;a href=&quot;https://github.com/NevaMind-AI/memU/pull/527&quot;&gt;#527&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Fixing duplicate and empty memorize input for OpenClaw: &lt;a href=&quot;https://github.com/NevaMind-AI/memU/pull/533&quot;&gt;#533&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These are all interesting, especially the last one. It made me decide to inspect the input classified by every adapter and its final output, looking at what redundancy each contains.&lt;/p&gt;
&lt;p&gt;And today I wrote [[RRF vs. Hybrid Search: How Should Time-Based Retrieval Be Blended, and How Does It Fit Project and Companion Scenarios?]] here, because debugging without pause makes me lose myself. I need to let things settle.&lt;/p&gt;
&lt;p&gt;There is another article in progress as well.&lt;/p&gt;
&lt;p&gt;But the source-code progress feels strange. The content of 0009, 00010, and 00011 is almost implemented, only rather hastily; all vibe has been doing intensive QA lately.&lt;/p&gt;
&lt;p&gt;Yet the Hybrid Search and BM25 promised in 0007 still have not landed, though the improvement should be substantial.&lt;/p&gt;
&lt;p&gt;I now want to align the source code and ADR documents, then see what gaps and mismatches there are in the implementation of 0009 and 00010.&lt;/p&gt;
&lt;p&gt;For example, the source code added a WorkBuddy adapter, which was unexpected.&lt;/p&gt;
&lt;p&gt;:::note[claude]&lt;/p&gt;
&lt;h3&gt;What aligns&lt;/h3&gt;
&lt;p&gt;The behavior declarations for the five hosts in ADR 0010 align with the source code line by line, with no deviation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Every host&apos;s session path, instruction-file path, &lt;code&gt;classify()&lt;/code&gt; semantics, and timestamp handling match the ADR table.&lt;/li&gt;
&lt;li&gt;Hermes really does open SQLite read-only with &lt;code&gt;?mode=ro&lt;/code&gt; (&lt;code&gt;hermes/sessions.py:72&lt;/code&gt;), and a test verifies that writes raise &lt;code&gt;OperationalError&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Cursor truly has no timestamp, inherits the base &lt;code&gt;timestamp()&lt;/code&gt; returning &lt;code&gt;None&lt;/code&gt;, and records null in the manifest.&lt;/li&gt;
&lt;li&gt;OpenClaw truly handles both ISO strings and epoch milliseconds in timestamps (&lt;code&gt;openclaw/sessions.py:82-93&lt;/code&gt;), distinguishing them with a &lt;code&gt;&amp;gt; 1e11&lt;/code&gt; threshold.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;TranscriptSource.exists()&lt;/code&gt; defaults to &lt;code&gt;root().is_dir()&lt;/code&gt;, while Hermes overrides it as &lt;code&gt;self._db.is_file()&lt;/code&gt;; both behave as ADR describes.&lt;/li&gt;
&lt;li&gt;At the configuration layer, &lt;code&gt;build_service_from_env()&lt;/code&gt; truly raises &lt;code&gt;ConfigError&lt;/code&gt; when &lt;code&gt;MEMU_DB&lt;/code&gt; is missing through &lt;code&gt;require()&lt;/code&gt; in &lt;code&gt;env.py:94-99&lt;/code&gt;; it does not silently fall back.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;What diverges&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;1. &lt;code&gt;memu retrieve&lt;/code&gt; is not at all the heavy LLM-routed path ADR 0009 describes&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;ADR 0009 spends considerable space on lines 89–92 emphasizing that the inject hook must &lt;strong&gt;never&lt;/strong&gt; call &lt;code&gt;memu retrieve&lt;/code&gt;, because it is an “LLM-routed path (intention routing, sufficiency checks, summarization), far too heavy to run on every turn.” It therefore needs a dedicated &lt;code&gt;progressive_retrieve&lt;/code&gt; path.&lt;/p&gt;
&lt;p&gt;But opening &lt;code&gt;src/memu/cli.py:92&lt;/code&gt; shows that &lt;code&gt;memu retrieve&lt;/code&gt; calls &lt;code&gt;service.progressive_retrieve()&lt;/code&gt;—the &lt;strong&gt;same function&lt;/strong&gt; called by host adapters through &lt;code&gt;memu-codex retrieve&lt;/code&gt;. The description at &lt;code&gt;cli.py:145&lt;/code&gt; even says &lt;code&gt;&quot;Single-shot embedding retrieval ... (LLM-free, fast)&quot;&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;In other words, the premise ADR 0009 uses to explain why host adapters need their own retrieve subcommand—that &lt;code&gt;memu retrieve&lt;/code&gt; is too heavy—&lt;strong&gt;does not exist in the code&lt;/strong&gt;. The heavy LLM-routed retrieval does not exist anywhere in the codebase. There is a hollow layer of reasoning between the ADR&apos;s architectural narrative and its implementation.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;2. “Every entry point calls &lt;code&gt;build_service_from_env()&lt;/code&gt;”—the &lt;code&gt;memu&lt;/code&gt; CLI itself does not&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;ADR 0009 lines 121–125 claim that “every entrypoint calls it: the &lt;code&gt;memu&lt;/code&gt; CLI, &lt;code&gt;memu-codex retrieve&lt;/code&gt;, and the bridging pipeline&apos;s prepare and commit.” The bridging pipeline does call it (&lt;code&gt;pipeline.py:55&lt;/code&gt; and &lt;code&gt;pipeline.py:103&lt;/code&gt;), and host-adapter retrieval does too (&lt;code&gt;retrieval.py:31&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;But the &lt;code&gt;memu&lt;/code&gt; CLI itself uses its own &lt;code&gt;_build_service()&lt;/code&gt; in &lt;code&gt;cli.py:68-83&lt;/code&gt;, constructing the service through argv parsing rather than &lt;code&gt;build_service_from_env()&lt;/code&gt;. It reads &lt;code&gt;config.env&lt;/code&gt; as a fallback, so the normal result is consistent—but this differs from ADR&apos;s claim of a single source of truth and one function serving every entry point. Two construction paths exist.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;3. &lt;code&gt;install-instruction&lt;/code&gt; and &lt;code&gt;remove-instruction&lt;/code&gt; are public CLI commands that ADR 0009 does not mention&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;ADR 0009 lists all host CLI verbs as &lt;code&gt;retrieve&lt;/code&gt;, &lt;code&gt;prepare&lt;/code&gt;, &lt;code&gt;commit&lt;/code&gt;, &lt;code&gt;verify-resources&lt;/code&gt;, &lt;code&gt;doctor&lt;/code&gt;, and &lt;code&gt;docs&lt;/code&gt;. But the actual shared CLI in &lt;code&gt;host_cli.py:3-5&lt;/code&gt; also has &lt;code&gt;install-instruction&lt;/code&gt; and &lt;code&gt;remove-instruction&lt;/code&gt;. These are registered in &lt;code&gt;instruction.py:294&lt;/code&gt; and &lt;code&gt;instruction.py:314&lt;/code&gt;, the entry points for users to install and remove instructions, rather than internal implementation details. ADR&apos;s scope description misses them.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;4. WorkBuddy is a sixth host adapter with no ADR coverage&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;pyproject.toml:69&lt;/code&gt; registers &lt;code&gt;memu-workbuddy&lt;/code&gt;, fully implemented in &lt;code&gt;src/memu/hosts/workbuddy/&lt;/code&gt;. Its session format resembles Codex but has different record types: &lt;code&gt;input_text&lt;/code&gt; / &lt;code&gt;output_text&lt;/code&gt;, and &lt;code&gt;function_call&lt;/code&gt; / &lt;code&gt;function_call_result&lt;/code&gt; as separate types. It completely follows the HostSpec pattern of 0010, but ADR 0010&apos;s table and text list only five hosts.
:::&lt;/p&gt;
&lt;p&gt;ADR 0009 says there should not be any heavy LLM retrieval, so all LLM Retrieve vanished overnight =-=.&lt;/p&gt;
&lt;p&gt;But the Hybrid Search promised in ADR 0007 seems about ready to land. We can recently implement wikimem&apos;s ADR too and start testing.&lt;/p&gt;
&lt;p&gt;ADR 00011 seems to involve a paradigm-level design. We will break it down separately later. It seems meant for a general scenario, and we can also look at how XnneHangLab should adopt this general paradigm.&lt;/p&gt;
&lt;p&gt;It is worth noting that every one of our adapters triggers retrieval through Skills, not on_prompt.&lt;/p&gt;
&lt;p&gt;Whether &lt;code&gt;CLAUDE.md&lt;/code&gt; or &lt;code&gt;AGENTS.md&lt;/code&gt;, they are not “absolutely safe.” Forgetting, laziness, and hallucination still happen in long documents.&lt;/p&gt;
&lt;p&gt;We added a &lt;a href=&quot;https://github.com/NevaMind-AI/memU/issues/507&quot;&gt;simple A/B test&lt;/a&gt; then.&lt;/p&gt;
</content:encoded></item><item><title>Go Build Long-Term Memory! A Review and Plan After Graduating with an AI Degree</title><link>https://xnnehang.top/en/posts/long-term-memory-graduation-review-and-plan/</link><guid isPermaLink="true">https://xnnehang.top/en/posts/long-term-memory-graduation-review-and-plan/</guid><description>A simple, ordinary story: an eighteen-year-old&apos;s dream inspired by Plastic Memories became a research topic at twenty-two—along with a technical survey of long-term memory, a plan for breaking down projects, and a look ahead at life.</description><pubDate>Sun, 28 Jun 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;img src=&quot;../../assets/img/graduation-review/graduation-review-cover.png&quot; alt=&quot;cover&quot; /&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;a href=&quot;https://blog.nagi.fun/2025-memo?lang=zh&quot;&gt;Go Build Robots! An Annual Review After Graduating with an AI Degree&lt;/a&gt; inspired this post. I want to begin with a RoadMap and a simple review of my undergraduate years, partly to ask myself: what am I truly pursuing?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;An Ordinary Story&lt;/h2&gt;
&lt;p&gt;In June 2022, X had just finished watching &lt;em&gt;Plastic Memories&lt;/em&gt;. Carrying a dream of a cyber girlfriend, he opened Xiaojia Yu’s introductory Python course, bought a copy of &lt;em&gt;Python Basics&lt;/em&gt; that he never carefully read before graduation, and happily applied to XMUT’s Artificial Intelligence program. ChatGPT 3.5 was released on November 30, 2022—less than three months later.&lt;/p&gt;
&lt;p&gt;During an online self-introduction after enrollment, X made a small animated introduction with Python’s pygame, but in the end he was still forced to turn on his microphone and speak. There was no escaping it; there really was no escaping it.&lt;/p&gt;
&lt;p&gt;In November 2022, X completed a creative C++ course project: hooking the message content of TIM (QQ) through its window handle and generating replies.&lt;/p&gt;
&lt;p&gt;&amp;lt;iframe src=&quot;https://player.bilibili.com/player.html?bvid=BV1wM411k7q9&amp;amp;page=1&amp;amp;autoplay=0&quot; scrolling=&quot;no&quot; border=&quot;0&quot; frameborder=&quot;no&quot; framespacing=&quot;0&quot; allowfullscreen=&quot;true&quot; style=&quot;height:100%;width:100%; aspect-ratio: 16 / 9;&quot;&amp;gt; &amp;lt;/iframe&amp;gt;&lt;/p&gt;
&lt;p&gt;That was the first time X realized that there was already a way to reply, but how could a reply have a soul? He then began studying PyTorch—CNN, ResNet, Transformer, ViT—and BERT on Udemy.&lt;/p&gt;
&lt;p&gt;Before X had even figured out what BERT was, ChatGPT 3.5 arrived. Soon, someone was using ChatGPT 3.5 + Live2D + VITS + Unity to build conversational virtual humans. Productivity really does rise when the goal is a cyber girlfriend.&lt;/p&gt;
&lt;p&gt;&amp;lt;iframe src=&quot;https://player.bilibili.com/player.html?bvid=BV1TD4y1E7e8&amp;amp;page=1&amp;amp;autoplay=0&quot; scrolling=&quot;no&quot; border=&quot;0&quot; frameborder=&quot;no&quot; framespacing=&quot;0&quot; allowfullscreen=&quot;true&quot; style=&quot;height:100%;width:100%; aspect-ratio: 16 / 9;&quot;&amp;gt; &amp;lt;/iframe&amp;gt;&lt;/p&gt;
&lt;p&gt;At the time, there were almost nothing but hard-coded system prompts and very short context windows, but to X it still felt close to a miracle.&lt;/p&gt;
&lt;p&gt;Around then, X was writing a ResNet classifier for anime characters in a higher-math class when the professor asked whether he wanted to join their lab; they had datasets there. X innocently went along. Then came weekly meetings, dataset cleaning, hyperparameter tuning, requests to improve some Net for a particular task, and, even during winter and summer breaks, the dreaded every-two-weeks question: &lt;code&gt;Any progress lately?&lt;/code&gt; Life as a graduate student began to cast a shadow over X.&lt;/p&gt;
&lt;p&gt;At the time, X silently swore never to pursue graduate school. After two rounds of revision, he did publish a paper on using Deep-LSTMs to predict the discharge time of COVID-19 patients. He also swore never to improve neural networks again: it was boring, time-consuming, a black box, and gave no feedback.&lt;/p&gt;
&lt;p&gt;To relax, X started playing with the VITS family, getting into BERT-VITS2 and GPT-SoVITS. This time he avoided the model networks themselves and only worked on development-oriented things. He trained a voice for a little Soyyo:&lt;/p&gt;
&lt;p&gt;&amp;lt;iframe src=&quot;https://player.bilibili.com/player.html?bvid=BV1g94y1L7re&amp;amp;page=1&amp;amp;autoplay=0&quot; scrolling=&quot;no&quot; border=&quot;0&quot; frameborder=&quot;no&quot; framespacing=&quot;0&quot; allowfullscreen=&quot;true&quot; style=&quot;height:100%;width:100%; aspect-ratio: 16 / 9;&quot;&amp;gt; &amp;lt;/iframe&amp;gt;&lt;/p&gt;
&lt;p&gt;He also wrote a tool for quickly making VITS-family datasets—although GPT-SoVITS later provided a better official one. Still, it was the first time X experienced the joy of open source. Even though the code was rough, he kept that repository pinned in his profile. It was his starting point.&lt;/p&gt;
&lt;p&gt;Not long afterward, X met &lt;a href=&quot;https://github.com/SigureMo&quot;&gt;SigureMo&lt;/a&gt;, who was something like X’s teacher. They did not teach him directly, but over two or three months X completely reshaped his coding workflow around theirs: ruff, pylint, pytest. He also absorbed their approach to code review: why do this, is there a better way, and is this the smallest change without loose ends?&lt;/p&gt;
&lt;p&gt;With SigureMo’s guidance, X also took part in Paddle’s Qihang program. There he first experienced what it felt like to work in a white box. Neural-network tuning gives no way to predict whether results will improve, but deep-learning-framework operator bug fixes or extra type support do. During that time, he was truly happy writing code. There were mishaps too: SigureMo wanted X to introduce typos through pre-commit and assigned X the reviews for those simple spelling fixes. But because X had never reviewed code before, he did not know that a review had to be submitted before anyone could see it. He left many reviews pending =-=. No one replied, and he was initially confused until SigureMo had to wrap them up every time; only then did X realize that no one could see his reviews.&lt;/p&gt;
&lt;p&gt;SigureMo always took good care of X and gave him the closeness of finding someone similar, though X must have caused SigureMo plenty of headaches. SigureMo has always been X’s mentor in open source.&lt;/p&gt;
&lt;p&gt;There were roughly two reasons X later left Paddle. First, X did not much like grinding LeetCode and found C++ and algorithmic principles difficult, so he could not directly take on high-star hackathon tasks. For example, he picked up an alignment task for the &lt;code&gt;torch.grad&lt;/code&gt; operator and got stuck for two weeks. If Claude Opus 4.6 had existed then, X could have worked through it piece by piece and learned from it, but at the time OpenAI only had GPT-4o, which was not very capable of reading Paddle. SigureMo did not work on operators like &lt;code&gt;torch.grad&lt;/code&gt; either—perhaps their math was not that good?—and X was afraid of troubling others. Was troubling SigureMo somehow acceptable? So X quietly cancelled the task assignment and quietly left.&lt;/p&gt;
&lt;p&gt;Was that the right thing to do? X does not know. But he decided that someday he would contribute to SigureMo’s &lt;a href=&quot;https://github.com/yutto-dev/yutto&quot;&gt;yutto&lt;/a&gt;. He also made a GUI version of yutto.&lt;/p&gt;
&lt;p&gt;&amp;lt;iframe src=&quot;https://player.bilibili.com/player.html?bvid=BV1yRdBBsEGZ&amp;amp;page=1&amp;amp;autoplay=0&quot; scrolling=&quot;no&quot; border=&quot;0&quot; frameborder=&quot;no&quot; framespacing=&quot;0&quot; allowfullscreen=&quot;true&quot; style=&quot;height:100%;width:100%; aspect-ratio: 16 / 9;&quot;&amp;gt; &amp;lt;/iframe&amp;gt;&lt;/p&gt;
&lt;p&gt;After leaving Paddle, the dream of a cyber girlfriend from the beginning of university slowly resurfaced. Even though half of X’s university years had already passed, he wanted to go all in and put all his energy into developing a desktop companion.&lt;/p&gt;
&lt;p&gt;That was how the XnneHangLab repository began. It is a story that is still continuing.&lt;/p&gt;
&lt;p&gt;This project used almost everything X had learned: TTS, ASR, Live2D, and Agents.&lt;/p&gt;
&lt;p&gt;On top of &lt;a href=&quot;https://github.com/Open-LLM-VTuber/Open-LLM-VTuber&quot;&gt;Open-LLM-VTuber&lt;/a&gt;, X added Skills, Tools, Memory, and proactive conversation. To do that, he built an Agent framework tailored to his own project—[[What We Built When Mainstream Agent Frameworks Could Not Fit Our Needs]].&lt;/p&gt;
&lt;p&gt;X used this project as his graduation project. Yet even while standing at the defense podium, he still had so many plans and expectations for the application: hoping DeepSeek V4.1 would bring multimodal visual understanding and reduce the LLM-call delay for proactive conversation to a single call; hoping to unravel the mysteries of long-term memory. For performance and time, he merely reused &lt;a href=&quot;https://github.com/mem0ai/mem0&quot;&gt;mem0&lt;/a&gt; for RAG and &lt;a href=&quot;https://github.com/zilliztech/memsearch&quot;&gt;memsearch&lt;/a&gt; for Markdown-file memory. He had not had time to think more deeply. There were too many reflective posts still unwritten, including [[After Building Long-Lived Systems: Is the RAG Monster Right for Constructing a Personal Blog Graph?]]. There was still more to break down: how should memory requirements really be built, what can be learned from others, and how should many repositories be unpacked—&lt;a href=&quot;https://github.com/AlfreScarlet/MoeChat&quot;&gt;AlfreScarlet/MoeChat&lt;/a&gt;, &lt;a href=&quot;https://github.com/Anson-Trio/BaiShou&quot;&gt;Anson-Trio/BaiShou&lt;/a&gt;? He had not yet properly considered how file-based memory and persona files should be arranged or layered; how they should be indexed; how documents read each time should be generated and organized; how context length should be controlled; how bidirectional references should work; or whether metadata + nodes are necessary.&lt;/p&gt;
&lt;p&gt;This story will continue, but X still has some time. Once again, he went all in: after graduation, he joined &lt;a href=&quot;https://github.com/NevaMind-AI&quot;&gt;NevaMind-AI&lt;/a&gt; as a remote developer in an internship-like role. Not full-time, not job hunting—but why? Because even if he joined a small company to do Agent development, repeatedly and mechanically using LangChain or LangGraph to build and maintain applications every day would be far less interesting than thinking about Agents themselves. Or perhaps it is not a question of interestingness. Will Agent development still follow that pattern in the future? Claude Fable 5 had been available for only a day, yet it had already made many people feel that future LLMs might not need manually authored workflows at all; perhaps the details of a workflow should be decided by the model itself. Perhaps people will only need to write requirements. Then the old form of Agent-development roles will change completely, and X will have to adjust direction—again falling into an anxious, involuntary state he had known well from the days of frequent sophomore-year group meetings.&lt;/p&gt;
&lt;p&gt;X still wants to make a cyber girlfriend; that is what keeps him moving. But after LLMs arrived, the question changed from how to make a model speak naturally to how to let it sustain, update, and maintain its persona and memory over time. That is what we will discuss next.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;A small interlude: just after X joined NevaMind AI, he unexpectedly received an invitation to talk from &lt;a href=&quot;https://ai-mage.jp/news&quot;&gt;https://ai-mage.jp&lt;/a&gt;. The invitation said: &lt;code&gt;AI Mage is building AGI (Anime General Intelligence) that deeply understands Japanese anime contexts, and is looking for a core development partner with strong engineering ability and an interest in anime / animation content.&lt;/code&gt; Was the combination of an Elaina avatar and a Frieren profile card somehow working its magic again? But X has given himself to the dream and cannot give himself to anyone else; right now he only wants to make a cyber girlfriend. More precisely, beyond the form a cyber girlfriend takes, he cares more about her soul.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;And this is a simple, ordinary story: a dream that began with &lt;em&gt;Plastic Memories&lt;/em&gt; at eighteen became a research topic at twenty-two.&lt;/p&gt;
&lt;h2&gt;The Plan&lt;/h2&gt;
&lt;p&gt;This section will probably keep being revised and expanded. It mainly revolves around long-term memory.&lt;/p&gt;
&lt;p&gt;First, I want to build a basic understanding of the different directions in LLM long-term memory:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Reinforcement learning + distilled internalization&lt;/strong&gt; — fold memories into model parameters. Rewards are sparse and the optimization space is large; I am not personally drawn to it, and its compute cost at runtime is too high to be practical.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Reflection &amp;amp; brain-inspired approaches&lt;/strong&gt; — follow neuroscience and cognitive science. They make for a compelling story; experiments determine the result. This may also provide guidance for how content is organized in Markdown.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Hierarchical memory&lt;/strong&gt; — short-, medium-, and long-term; L1/L2/L3. This is currently the mainstream approach, though I do not know it well yet.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Knowledge graphs &amp;amp; vector spaces &amp;amp; RAG&lt;/strong&gt; — if it is only simple CRUD, there is not much to see. Text chunks embedded as vectors are fragmented in themselves, and the relationships produced by vector similarity are also inarticulate.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;File-system-style memory&lt;/strong&gt; — organizing memory with Markdown + folders. This is also the direction I am trying now, and perhaps MemU’s position too? But the specific layers and indexes still need study.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;After I understand these directions to some degree, I may need to find a representative example for each: mem0 for RAG, BaiShou for L1/L2/L3, and papers for brain-inspired approaches. Then I can study the trade-offs and design philosophies of open-source Memory Agent projects and papers, and identify what is worth learning from.&lt;/p&gt;
&lt;p&gt;Because the points we must always balance are when long-running memory retrieval is allowed and when we want to reply as quickly as possible. There is no best memory system, only the most suitable one.&lt;/p&gt;
&lt;h3&gt;Breaking Down Memory Agent Projects&lt;/h3&gt;
&lt;p&gt;::github{repo=&quot;AlfreScarlet/MoeChat&quot;}&lt;/p&gt;
&lt;p&gt;::github{repo=&quot;Anson-Trio/BaiShou&quot;}&lt;/p&gt;
&lt;p&gt;::github{repo=&quot;zilliztech/memsearch&quot;}&lt;/p&gt;
&lt;p&gt;For now, these are the ones on the list. MemU is included too, of course, because I will later take part in refactoring-oriented development.&lt;/p&gt;
&lt;p&gt;But I think that, rather than immersing yourself in one project, it can sometimes be more beneficial to look at more projects and break down more of them. Now, Claude can arguably write code in our place, but what we should write deserves careful thought. And that is usually not something we can devise by sitting still; it is better to see more and reflect more.&lt;/p&gt;
&lt;p&gt;The project breakdowns will become a blog series and will gradually make their way into my own XnneHangLab.&lt;/p&gt;
&lt;h3&gt;Sleep &amp;amp; Fitness&lt;/h3&gt;
&lt;p&gt;The night before the graduation ceremony, my roommate and I talked late into the night.&lt;/p&gt;
&lt;p&gt;We spoke about the feeling of gradually losing control over ourselves through revenge bedtime procrastination caused by stress, and about how going to bed at ten for several days in a row made us feel smarter and more able to act.&lt;/p&gt;
&lt;p&gt;Because I work remotely and do not yet know what the workload will be like, I cannot draw conclusions for now. I only hope I can keep going to bed early.&lt;/p&gt;
&lt;p&gt;As for fitness, I should probably do cardio for a month first, then consider getting a gym membership. If the weather is not good—recently it really seems not to be—I may need to get one early, or buy a treadmill myself.&lt;/p&gt;
&lt;h3&gt;Games &amp;amp; Recording&lt;/h3&gt;
&lt;p&gt;As graduation approached, I did not lament wasting time by failing to study more. Instead, I lamented wasting time by failing to play more games. Why?&lt;/p&gt;
&lt;p&gt;Teamfight Tactics and Valorant, for example: games that require multiple people, offer achievement through rank, and provide enjoyment through gaming companions become dull after you leave those companions or finally reach your rank ceiling. Or perhaps those games are dull in themselves, and only feel interesting because of the company.&lt;/p&gt;
&lt;p&gt;They also taught me a philosophy: happiness does not come from expectation, but from experience after beginning. A book may not look interesting at first, but once you actively read a few pages, you will often keep reading many more. Once many things begin, they do not easily stop. In games this may waste time, but the phenomenon itself can be used.&lt;/p&gt;
&lt;p&gt;I hope to keep playing games such as &lt;em&gt;Fengxin Tower&lt;/em&gt;, &lt;em&gt;Volcano Princess&lt;/em&gt;, &lt;em&gt;Chinese-Style Blind Date&lt;/em&gt;, and &lt;em&gt;Red Dead Redemption 2&lt;/em&gt;, and, if I can, write down some impressions.&lt;/p&gt;
&lt;p&gt;For example, I recently added &lt;em&gt;Dreamy Magical Princess&lt;/em&gt; to my library but have still not played it, and &lt;em&gt;Daughter of the Bright Moon&lt;/em&gt; will be released later. It is the summer sale now: add more games, experience more things.&lt;/p&gt;
&lt;p&gt;I hope that, this time, the wish to experience more interesting games will not remain only a fantasy or regret. Or even if it does, I should consciously leave more records like [[Fengxin Is a Good Name]].&lt;/p&gt;
&lt;h3&gt;Novels, Films, and Afterthoughts&lt;/h3&gt;
&lt;p&gt;I read far fewer physical novels during university than I did in my three years of high school.&lt;/p&gt;
&lt;p&gt;That includes the Raspberry Pi + projector setup I tinkered with in my sophomore year. After I finished setting it up, I did not watch more than ten films.&lt;/p&gt;
&lt;p&gt;&amp;lt;iframe src=&quot;https://player.bilibili.com/player.html?bvid=BV17zDWYwEj8&amp;amp;page=1&amp;amp;autoplay=0&quot; scrolling=&quot;no&quot; border=&quot;0&quot; frameborder=&quot;no&quot; framespacing=&quot;0&quot; allowfullscreen=&quot;true&quot; style=&quot;height:100%;width:100%; aspect-ratio: 16 / 9;&quot;&amp;gt; &amp;lt;/iframe&amp;gt;&lt;/p&gt;
&lt;p&gt;Keep writing after watching~&lt;/p&gt;
&lt;p&gt;But not just to write for writing’s sake.&lt;/p&gt;
&lt;h2&gt;Finally&lt;/h2&gt;
&lt;p&gt;Thank you for reading this far~&lt;/p&gt;
&lt;p&gt;I hope we can still be adorable in the future~&lt;/p&gt;
&lt;p&gt;And I hope adorable things keep drawing us in~&lt;/p&gt;
</content:encoded></item><item><title>What We Built When Mainstream Agent Frameworks Could Not Fit Our Needs</title><link>https://xnnehang.top/en/posts/agent-framework-exploration/</link><guid isPermaLink="true">https://xnnehang.top/en/posts/agent-framework-exploration/</guid><description>Drawing on our experience building an AI companionship engine, this article compares the limitations of mainstream Agent frameworks such as LangChain, Dify, LangGraph, and Coze, and documents the core design ideas and trade-offs behind the low-level framework we built for real-time companionship.</description><pubDate>Tue, 23 Jun 2026 00:00:00 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;[!NOTE]
&lt;strong&gt;AI collaboration disclosure:&lt;/strong&gt; This article was co-written by Xnne and &lt;a href=&quot;https://github.com/xnne-bot&quot;&gt;Korewaxnne&lt;/a&gt;, an AI assistant powered by Claude Opus 4.6. Xnne provided the hands-on technical experience, product thinking, and core design decisions; Korewaxnne helped organize the article&apos;s structure and technical explanations.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;We looked into every mainstream Agent framework we could find, from LangChain/LangGraph to Dify/n8n and from OpenHands/Suna to Claude Code, but not one of them fit our product requirements perfectly. Eventually, we realized that the question was not “Which framework should we choose?” but rather: &lt;strong&gt;What should you do when the abstraction boundaries of mainstream frameworks do not align with your product requirements?&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;An Uncommon Agent Scenario&lt;/h2&gt;
&lt;p&gt;Most Agent framework demos follow the same pattern: the user asks a question, the LLM reasons, calls a tool, and returns an answer. One question, one answer—clean and straightforward.&lt;/p&gt;
&lt;p&gt;Our scenario is entirely different. We are building an AI companionship engine for character roleplay, VTuber interaction, and gaming companions. A complete conversational turn for our Agent therefore involves far more than “calling an LLM.” It spans three very different stages, each with its own technical requirements:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Before the call:&lt;/strong&gt; The system does not wait for the user to speak before responding. In the gaming-companion scenario, a proactive OCR conversation plugin continuously polls the screen. When it detects an important in-game event—such as the character dying, a quest being completed, or the scene changing—it proactively prompts the LLM to start a conversation instead of waiting for the user. The framework must therefore support “conversation turns not initiated by the user.”&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;During the call:&lt;/strong&gt; The LLM&apos;s streaming output cannot simply be concatenated into a complete string and returned. Every token must enter a sentence segmenter in real time. As soon as a natural sentence is formed, it is sent to a GPT-SoVITS / Qwen-TTS engine for speech synthesis, while emotion tags are extracted to drive changes in the Live2D model&apos;s expression. This is a token-level fan-out pipeline with extremely tight latency requirements. Within the same turn, the LLM may also call multiple tools—for web searches, file operations, or screenshot analysis—and resume streaming afterward. &lt;strong&gt;Even the tokens for a tool call are not accumulated into complete JSON before being parsed. The framework parses structured events as the tokens stream in and emits them alongside text tokens in the same stream.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;After the call:&lt;/strong&gt; Finishing a turn does not mean simply saving it to SQLite and calling it done. The conversation is sent to the Memory Bench service, where mem0 extracts and aggregates memories while Neo4j stores them in a knowledge graph, forming structured long-term memory. Before the next conversation begins, those memories are retrieved and injected back into the context.&lt;/p&gt;
&lt;p&gt;These three stages define the core requirements of our framework. Next, let us see what happens when we try to fit mainstream frameworks around them.&lt;/p&gt;
&lt;h2&gt;The Trouble with Mainstream Frameworks&lt;/h2&gt;
&lt;h3&gt;Coze: The Low-Code Ceiling&lt;/h3&gt;
&lt;p&gt;Coze is an Agent-building platform launched by ByteDance; in 2024, it open-sourced its core engine as Coze Studio. Its design goal is clear: enable nontechnical users to build AI bots through a visual interface and quickly deploy them to platforms such as WeChat, Feishu, and Discord.&lt;/p&gt;
&lt;p&gt;Coze&apos;s Workflow editor uses drag-and-drop nodes to orchestrate processes. Together with its built-in plugin marketplace and knowledge bases, it really can produce a functional customer-service bot or knowledge Q&amp;amp;A assistant within minutes. This is where Coze genuinely excels.&lt;/p&gt;
&lt;p&gt;But it runs into a wall in our scenario. First, Coze Workflow has an explicit limitation: it does not support an end node with streaming output within a workflow. That prevents us from segmenting and dispatching text to TTS at the token level, breaking the entire speech-synthesis stage. Second, although Coze&apos;s plugin system supports third-party APIs, its lifecycle follows a request-response model and has no hooks such as &lt;code&gt;on_before_turn&lt;/code&gt; or &lt;code&gt;on_after_turn&lt;/code&gt;. There is nowhere in Coze&apos;s architecture to attach our proactive OCR trigger or post-call memory graph construction. Finally, Coze&apos;s open-source community edition and commercial edition differ in functionality. Features such as custom voices are available only in the commercial edition, whereas we need a fully controllable TTS pipeline.&lt;/p&gt;
&lt;p&gt;In short, Coze was designed for “chatbots,” not “companion Agents.”&lt;/p&gt;
&lt;h3&gt;Dify: The Limits of Workflow Expressiveness&lt;/h3&gt;
&lt;p&gt;Dify is an excellent LLMOps platform whose core value lies in visual workflow orchestration and all-in-one RAG management. By dragging and dropping nodes, you can quickly build an Agent application with knowledge-base retrieval, model switching, and conditional branches. Dify&apos;s Agent Node even supports custom strategy plugins such as ReAct, CoT, and ToT, while its Plugin Trigger mechanism can subscribe to external events that start a workflow.&lt;/p&gt;
&lt;p&gt;At first glance, Dify&apos;s Plugin Trigger seems capable of meeting our need for “proactive OCR triggers”: subscribe to an external OCR event and use it to start the workflow. The problem appears downstream.&lt;/p&gt;
&lt;p&gt;Dify&apos;s Agent Node follows a three-stage execution model: initialization, iterative loop, and final response. Each iteration is a complete LLM call. Its output is a structured JSON response rather than the token stream we need. Although Dify&apos;s Chat API supports streaming over SSE, that stream operates at the node level: you can see the result after a node finishes, but you cannot access the LLM&apos;s output token by token as it is generated and segment it in real time.&lt;/p&gt;
&lt;p&gt;The more consequential limitation concerns memory. Dify&apos;s Agent Node uses &lt;code&gt;TokenBufferMemory&lt;/code&gt; to manage context through a sliding token window. That works well for cost control, but we need semantic retrieval from an external knowledge graph: use the current conversation to recall relevant memory fragments from Neo4j, then inject them at a specific point in the user prompt. This bidirectional memory flow—retrieval before the call and graph construction afterward—falls outside the design scope of Dify&apos;s Agent Node.&lt;/p&gt;
&lt;p&gt;What is Dify well suited to? Enterprise RAG applications, customer-service workflows, and content-generation pipelines—scenarios that are not sensitive to streaming granularity and whose memory requirements involve “recall within a window” rather than “cross-session graph relationships.”&lt;/p&gt;
&lt;h3&gt;LangChain: The Cost of Abstraction&lt;/h3&gt;
&lt;p&gt;LangChain was an early mover in the Agent framework space. Its greatest contribution was defining the concept of a “Chain”: a composable pipeline connecting a Prompt, an LLM, an Output Parser, and Tools. In 2023 and 2024, this abstraction dramatically lowered the barrier to building LLM applications.&lt;/p&gt;
&lt;p&gt;LangChain&apos;s central strengths are composability and its ecosystem. It offers the broadest collection of Integrations, with official adapters for hundreds of third-party tools and vector databases; a mature Document Loader / Text Splitter / Retriever stack for RAG; and LangSmith for Tracing and Eval. If you are building a conventional retrieval-augmented Q&amp;amp;A or document-analysis application, LangChain may still be the fastest place to start.&lt;/p&gt;
&lt;p&gt;Yet LangChain&apos;s problem lies precisely in its core abstraction.&lt;/p&gt;
&lt;p&gt;A Chain is linear. A standard LangChain Agent works like this: receive input → construct a Prompt → call the LLM → parse its output → execute a tool if needed → call the LLM again → produce the final output. It is a one-way pipeline. Our scenario, however, requires the token stream to be handled by several consumers simultaneously while the LLM is generating: a sentence segmenter, an action extractor, a TTS filter, and a frontend display processor. Tool calls can also interrupt the text stream, insert tool-status labels, and then resume streaming after execution finishes.&lt;/p&gt;
&lt;p&gt;This is not a chain. It is a stream with loops, branches, interruptions, and resumptions.&lt;/p&gt;
&lt;p&gt;More concretely, LangChain&apos;s &lt;code&gt;AgentExecutor&lt;/code&gt;, which was marked deprecated by the end of 2025, blocks the entire chain while a tool call is executing. You have no opportunity to stream status information to the frontend during that execution. When our &lt;code&gt;AgentCore&lt;/code&gt; encounters a tool call, it first yields a structured &lt;code&gt;ToolCallEvent(status=&quot;running&quot;)&lt;/code&gt; event so the frontend can immediately display the tool&apos;s status. It then executes all tool calls concurrently, yields &lt;code&gt;ToolCallEvent(status=&quot;completed&quot;)&lt;/code&gt; when they finish, and resumes streaming generation. Throughout the process, text tokens and tool events flow out of the same &lt;code&gt;AsyncIterator&lt;/code&gt; as distinct types for the frontend to consume separately.&lt;/p&gt;
&lt;p&gt;LangChain&apos;s memory abstractions, such as &lt;code&gt;ConversationBufferMemory&lt;/code&gt; and &lt;code&gt;ConversationSummaryMemory&lt;/code&gt;, were likewise designed for simpler scenarios. They assume memory is “some compressed form of the conversation history” that can simply be placed in the Prompt. Our memory is an independent service with its own search and write APIs. It must be queried asynchronously before a conversation begins and written to asynchronously after it ends. LangChain provides no native lifecycle hooks for this kind of external asynchronous memory service.&lt;/p&gt;
&lt;p&gt;Finally, LangChain has too many abstraction layers. A tool call passes through &lt;code&gt;Tool&lt;/code&gt; → &lt;code&gt;ToolKit&lt;/code&gt; → &lt;code&gt;AgentExecutor&lt;/code&gt; → &lt;code&gt;OutputParser&lt;/code&gt; and several layers of wrapping. During debugging, you often need to follow five or six nested Traces in LangSmith just to locate the problem. In a real-time streaming scenario like ours, where optimization happens at the millisecond level, every abstraction layer adds latency and debugging overhead.&lt;/p&gt;
&lt;h3&gt;LangGraph: The Closest Match, Yet Still Misaligned&lt;/h3&gt;
&lt;p&gt;LangGraph is the LangChain team&apos;s answer to the limitations of its own linear architecture. It introduces a directed graph, &lt;code&gt;StateGraph&lt;/code&gt;, for orchestrating Agent workflows and supports complex control flow such as loops, branches, conditional edges, and human approval. Since LangChain and LangGraph both reached their 1.0 milestones in October 2025, LangChain&apos;s &lt;code&gt;create_react_agent()&lt;/code&gt; has in fact run on top of the LangGraph engine.&lt;/p&gt;
&lt;p&gt;Several LangGraph design choices are genuinely worth learning from. Its concept of State—a shared state object passed between graph nodes—offers more flexible data transfer than a LangChain Chain. Time-Travel Debugging lets you return to any node in a graph execution and replay it, which is extremely useful when debugging complex workflows. Its Human-in-the-Loop mechanism lets you insert human approval on any edge in the graph.&lt;/p&gt;
&lt;p&gt;But there is a fundamental mismatch between LangGraph&apos;s graph model and our requirements: granularity.&lt;/p&gt;
&lt;p&gt;A LangGraph Node represents “one complete operation”: one LLM call, one tool execution, or one decision. Nodes pass State to one another through Edges. This design is ideal for orchestrating multistep workflows such as “retrieve documents, summarize them, generate a report, and send it after human approval.”&lt;/p&gt;
&lt;p&gt;Our core requirement, however, is not “orchestration between steps” but “token-level processing within a single LLM call.” As the LLM streams its output, every token must pass through a four-layer decorator pipeline: &lt;code&gt;sentence_divider → actions_extractor → tts_filter → display_processor&lt;/code&gt;. This is not “one graph node finishes and passes its result to the next.” It is “the output stream is split and processed in real time inside a single node.” LangGraph&apos;s State Graph cannot express behavior at this granularity.&lt;/p&gt;
&lt;p&gt;Moreover, our Hook system needs “lifecycle hooks for a conversational turn,” not “hooks for graph-execution nodes.” &lt;code&gt;on_before_turn&lt;/code&gt; retrieves memories before the entire graph begins, &lt;code&gt;on_after_turn&lt;/code&gt; writes memories after the graph finishes, and &lt;code&gt;on_after_playback&lt;/code&gt; is not triggered until frontend playback ends, because some post-processing must wait for TTS playback to finish. These three hooks span three entirely different timescales: the LLM call, tool execution, and frontend playback. LangGraph&apos;s graph is designed around the “LLM + Tool” execution flow; it has no concept of “frontend playback complete.”&lt;/p&gt;
&lt;p&gt;LangGraph also has a practical problem at scale: performance. As the number of graph nodes and edges grows, execution slows, memory usage rises, and debugging becomes harder. Its tight coupling to the LangChain ecosystem also means that if you want to use a lighter-weight LLM client, such as the &lt;code&gt;openai&lt;/code&gt; SDK directly, you must write a great deal of glue code to adapt it.&lt;/p&gt;
&lt;h3&gt;Harness Engineering: The Right Direction, but We Do Not Need a Control Plane&lt;/h3&gt;
&lt;p&gt;The hottest concept of 2026 is Harness Engineering: “Models provide raw intelligence; harnesses make that intelligence useful.” Gartner predicts that by the end of 2026, 40% of enterprise applications will include AI Agents, while flaws in the harness layer rather than inadequate model reasoning will account for 65% of Agent project failures.&lt;/p&gt;
&lt;p&gt;Microsoft Agent Framework (MAF) reached 1.0 GA in April 2026, unifying AutoGen and Semantic Kernel while providing production-grade capabilities such as Shell access, human approval flows, and cross-session context management. The industry is also standardizing around two protocols: MCP (Model Context Protocol) for vertical interaction between Agents and Tools, and A2A (Agent-to-Agent) for horizontal delegation.&lt;/p&gt;
&lt;p&gt;The five layers emphasized by Harness Engineering—tool orchestration, validation loops, context and memory, guardrails, and observability—align closely with our own practice. Yet these frameworks typically assume either a “single-turn request-response” or “multistep workflow” model, with security, compliance, and observability as their central concerns. They are control planes designed for scenarios such as enterprise SRE, customer-service automation, and code generation.&lt;/p&gt;
&lt;p&gt;What we need is not a control plane, but a “presentation layer that lets an Agent accompany you like a person”: real-time speech, facial expressions, proactive conversation, and emotional memory. None of these requirements appear on the Roadmap of any Harness Engineering framework.&lt;/p&gt;
&lt;h2&gt;So What Did We Build?&lt;/h2&gt;
&lt;p&gt;Since nothing fit, we worked backward from our product requirements and built our own low-level architecture. It is not another “general-purpose Agent framework,” but an Agent engine designed for real-time companionship.&lt;/p&gt;
&lt;p&gt;Its core design rests on four pillars:&lt;/p&gt;
&lt;h3&gt;Lifecycle Hooks (Hook System)&lt;/h3&gt;
&lt;p&gt;We defined three hook points that cover the full lifecycle of a conversational turn:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;class HookPlugin(ABC):
    async def on_before_turn(self, user_text, ctx) -&amp;gt; str | None:
        &quot;&quot;&quot;Before the call: retrieve memories and inject context&quot;&quot;&quot;
    async def on_after_turn(self, user_text, assistant_text, ctx) -&amp;gt; None:
        &quot;&quot;&quot;After the call: write memories and update the graph&quot;&quot;&quot;
    async def on_after_playback(self, user_text, assistant_text, ctx) -&amp;gt; None:
        &quot;&quot;&quot;After playback: post-process once TTS playback has finished&quot;&quot;&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;MemoryPlugin&lt;/code&gt; is a typical implementation. In &lt;code&gt;on_before_turn&lt;/code&gt;, it performs a semantic search against the Memory Bench service and injects the recalled memory fragments into the context. In &lt;code&gt;on_after_turn&lt;/code&gt;, it asynchronously writes the current conversation to mem0 for memory extraction while updating the Neo4j knowledge graph.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;MoodChatPlugin&lt;/code&gt; implements a different pattern. Rather than responding passively, it schedules conversations proactively according to an emotion score: it talks more when happy and stays quiet when feeling low. In gaming-companion mode, it also uses OCR change detection to decide whether to speak first.&lt;/p&gt;
&lt;p&gt;One key design decision is that hook return values are concatenated and injected into the &lt;code&gt;[memory context]&lt;/code&gt; block of the user prompt rather than the system prompt. This avoids treating transient information as stable fact.&lt;/p&gt;
&lt;h3&gt;Streaming Tool-Calling Loop&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;AgentCore.run_turn()&lt;/code&gt; implements a multiround streaming tool-calling loop with a maximum of six iterations per turn. Its return type is &lt;code&gt;AsyncIterator[str | ToolCallEvent]&lt;/code&gt;: text tokens flow out as strings, while tool calls flow out as structured events.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;max_rounds = 6  # A safety guardrail, not a technical limit

for _ in range(max_rounds):
    text_buf = &quot;&quot;
    async for chunk in chat_llm.stream_with_tools(messages, tools=schema):
        if delta.content:
            text_buf += delta.content
            yield delta.content              # Emit text tokens immediately
        if delta.tool_calls:
            accumulate(tool_calls_buf)       # Accumulate tool-call fragments

    ordered_tool_calls = _ordered_complete_tool_calls(tool_calls_buf)
    if not _should_execute_tool_calls(finish_reason, ordered_tool_calls):
        break   # No tools need to run; finish normally

    # Before execution: emit running status events
    for tc in ordered_tool_calls:
        yield ToolCallEvent(
            tool_id=tc[&quot;id&quot;],
            tool_name=tc[&quot;name&quot;],
            args=tc[&quot;arguments&quot;],
            status=&quot;running&quot;,
        )

    # Execute all tools concurrently
    results = await asyncio.gather(
        *(_exec_tool(tc, tool_manager, ctx) for tc in ordered_tool_calls)
    )

    # After execution: emit completed / error status events
    for tc_info, result in zip(ordered_tool_calls, results):
        yield ToolCallEvent(
            tool_id=tc_info[&quot;id&quot;],
            tool_name=tc_info[&quot;name&quot;],
            args=tc_info[&quot;arguments&quot;],
            status=&quot;completed&quot; if result.ok else &quot;error&quot;,
            result=result_text,
        )

    # Append tool results to the message list, then let the LLM continue
    # generating from those results in the next round
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;The six-round limit is an empirical trade-off between latency and capability.&lt;/strong&gt; Voice interactions are sensitive to response time, while nearly all normal conversations finish after one or two rounds of tool calls—search → read a file → answer. Six rounds provide ample headroom without making users feel that they are waiting too long.&lt;/p&gt;
&lt;p&gt;Two design details are worth emphasizing.&lt;/p&gt;
&lt;p&gt;First, tool-call events flow out as &lt;strong&gt;structured objects&lt;/strong&gt;, not textual tags. &lt;code&gt;ToolCallEvent&lt;/code&gt; is a dataclass with fields including &lt;code&gt;tool_id&lt;/code&gt;, &lt;code&gt;tool_name&lt;/code&gt;, &lt;code&gt;args&lt;/code&gt;, &lt;code&gt;status&lt;/code&gt;, and &lt;code&gt;result&lt;/code&gt;. Neither the frontend nor any downstream pipeline layer has to recognize tool events by parsing text tags with regular expressions; each can simply check the type. Tool status is also split into two event stages: &lt;code&gt;status=&quot;running&quot;&lt;/code&gt; before execution and &lt;code&gt;status=&quot;completed&quot;&lt;/code&gt; or &lt;code&gt;&quot;error&quot;&lt;/code&gt; afterward. The frontend can switch its UI according to the current status.&lt;/p&gt;
&lt;p&gt;Second, multiple tool calls within the same round execute concurrently through &lt;code&gt;asyncio.gather()&lt;/code&gt; rather than waiting serially.&lt;/p&gt;
&lt;h3&gt;Token-Level Output Pipeline&lt;/h3&gt;
&lt;p&gt;The mixed &lt;code&gt;str | ToolCallEvent&lt;/code&gt; stream emitted by &lt;code&gt;AgentCore&lt;/code&gt; enters the decorator pipeline in &lt;code&gt;MemoryAgent&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;@tts_filter(config)           # Filter content TTS does not need (special symbols, etc.)
@display_processor(...)        # Process control tags for frontend display
@actions_extractor(live2d)     # Extract emotion/action tags to drive Live2D
@sentence_divider(...)         # Split on natural sentences and emit each immediately
async def chat_with_memory(input_data):
    async for token in core.run_turn(...):
        yield token
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The processing logic in every decorator layer performs one crucial check:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;async for chunk in stream:
    if isinstance(chunk, (AudioOutput, ToolCallEvent)):
        yield chunk         # Pass structured events through unchanged
        continue
    # Otherwise, process the text token in this layer
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As a structured event, &lt;code&gt;ToolCallEvent&lt;/code&gt; &lt;strong&gt;passes transparently through&lt;/strong&gt; the pipeline. The sentence segmenter does not split it, the TTS filter does not try to synthesize it, and the display processor does not attach tags to it. Whenever a layer encounters a &lt;code&gt;ToolCallEvent&lt;/code&gt;, it simply yields the event unchanged. The final stream received by the frontend contains two kinds of messages: processed sentences, including display text, TTS text, and action tags; and structured tool-call events. This is much cleaner than the early design, now removed, that mixed &lt;code&gt;&amp;lt;tool&amp;gt;[name]&amp;lt;/tool&amp;gt;&lt;/code&gt; text tags into the conversation stream.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;sentence_divider&lt;/code&gt; is the most latency-sensitive part of the pipeline. As soon as it has enough tokens to form a natural sentence, it yields that sentence immediately rather than waiting for the entire passage. This allows the TTS engine to begin synthesizing the first half of a response while the LLM is still generating the second, greatly reducing the delay users perceive before hearing the first sentence.&lt;/p&gt;
&lt;h3&gt;Four Plugin Types&lt;/h3&gt;
&lt;p&gt;All capabilities are extended through plugins. We defined four plugin types:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Type&lt;/th&gt;
&lt;th&gt;Responsibility&lt;/th&gt;
&lt;th&gt;Examples&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;tool&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Register callable tools&lt;/td&gt;
&lt;td&gt;&lt;code&gt;web_fetch&lt;/code&gt;, &lt;code&gt;screen_shot&lt;/code&gt;, &lt;code&gt;web_search_ddg&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;hook&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Provide lifecycle hooks&lt;/td&gt;
&lt;td&gt;&lt;code&gt;memory&lt;/code&gt; (memory retrieval + persistence), &lt;code&gt;mood_chat&lt;/code&gt; (proactive conversation)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;policy&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Inject prompt rules&lt;/td&gt;
&lt;td&gt;&lt;code&gt;pre_tool_preview&lt;/code&gt; (announce tool calls in advance), &lt;code&gt;tool_call_integrity&lt;/code&gt; (prevent hallucinated calls)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;skill&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Inject behavioral guidance&lt;/td&gt;
&lt;td&gt;&lt;code&gt;diary&lt;/code&gt; (workflow for reading and writing diary entries)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Each plugin declares its identity and default configuration in a &lt;code&gt;plugin.toml&lt;/code&gt; file:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[plugin]
id = &quot;memory&quot;
type = &quot;hook&quot;

[config]
base_url = &quot;http://localhost:12393&quot;
user_id = &quot;xnne&quot;
agent_id = &quot;congyin&quot;
search_limit = 10
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A Profile TOML file determines which plugins are enabled and which configuration values they override:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[plugins]
enabled = [&quot;web_search_ddg&quot;, &quot;web_fetch&quot;, &quot;memory&quot;, &quot;diary&quot;]

[plugins.memory]
agent_id = &quot;baoqiao&quot;     # Switch agent_id when switching characters
search_limit = 5
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This means the same codebase can switch to an entirely different Agent persona simply by changing the Profile file: a different character Prompt, output format, set of enabled plugins, and memory space. Two characters can coexist in the same Neo4j graph while remaining isolated from one another through &lt;code&gt;agent_id&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;The Trade-offs We Made&lt;/h2&gt;
&lt;p&gt;Every framework design involves trade-offs. To be honest, we gave up several things:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;We gave up MCP.&lt;/strong&gt; Early on, we used the MCP protocol for tool calls, but later migrated everything to in-process &lt;code&gt;BuiltinTool&lt;/code&gt;s. The reason is practical: MCP uses interprocess communication over JSON-RPC. For frequent operations such as “read a file” or “get the current time,” the IPC overhead is not worthwhile. In-process calls have microsecond-level latency; MCP operates at the millisecond level. In real-time voice interactions, those milliseconds accumulate into noticeable stuttering.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;We gave up a separate Tool Model.&lt;/strong&gt; We initially used a dedicated small model to make tool-calling decisions while the chat model focused solely on generating text. We later found that mainstream models&apos; native function calling had become good enough, and maintaining an additional tool model introduced far more complexity than benefit. PR #295 / #296 made this simplification and removed a series of components, including &lt;code&gt;AgentToolLoop&lt;/code&gt; and &lt;code&gt;AgentToolLoopRunner&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;We gave up generality.&lt;/strong&gt; We do not intend for this framework to fit every scenario. It contains extensive customization for real-time companionship—streaming sentence segmentation, a TTS pipeline, Live2D control, and emotion extraction—none of which is useful in a RAG question-answering or code-generation scenario. This is an opinionated framework, not a universal one.&lt;/p&gt;
&lt;h2&gt;Returning to the Original Question&lt;/h2&gt;
&lt;p&gt;What should a good low-level Agent framework look like?&lt;/p&gt;
&lt;p&gt;Our experience gives this answer: &lt;strong&gt;It should work backward from product requirements, not forward from abstract concepts.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;LangChain&apos;s Chain, LangGraph&apos;s StateGraph, and Dify&apos;s Workflow Node all begin with an abstraction and ask users to fit their requirements inside it. When your requirements happen to fall within the abstraction&apos;s scope—linear Q&amp;amp;A, multistep workflows, or RAG retrieval—they are highly effective. But once your requirements cross its boundaries—when you need a token-level streaming pipeline, lifecycle hooks spanning the three timescales of LLM, Tool, and Frontend, or declarative plugin configuration capable of switching an Agent&apos;s entire behavior—these frameworks turn from “accelerators” into “obstacles.”&lt;/p&gt;
&lt;p&gt;If we had to summarize the pattern, our experience would be:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Define a lifecycle, not an execution graph.&lt;/strong&gt; Before the call, during the call, after the call, and after playback: each stage has explicit hook points, and plugins decide where to attach themselves. This is more flexible than drawing an execution graph because the timescales of a real product often extend beyond the LLM call itself.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Streaming first, not request-response first.&lt;/strong&gt; From LLM calls and tool-status feedback to TTS synthesis, every stage is a stream driven by &lt;code&gt;AsyncIterator&lt;/code&gt;. Blocking designs are fatal in real-time scenarios.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Declarative configuration, not orchestration in code.&lt;/strong&gt; A &lt;code&gt;plugin.toml&lt;/code&gt; declares a plugin&apos;s identity; a &lt;code&gt;profile.toml&lt;/code&gt; declares the scenario&apos;s configuration. Switching an Agent&apos;s behavior means changing a file, not rewriting code.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Keep plugins isolated, but let them declare dependency chains.&lt;/strong&gt; Plugins cannot import one another; shared logic must be elevated into the framework layer. Isolation does not mean there are no relationships, however. Some plugins genuinely require others as prerequisites: &lt;code&gt;mood_chat&lt;/code&gt;, for example, depends on &lt;code&gt;vision_boost&lt;/code&gt;. We distinguish &lt;strong&gt;prerequisites&lt;/strong&gt; from &lt;strong&gt;dependents&lt;/strong&gt;: if A is a prerequisite of B, then B is a dependent of A. Installing a dependent plugin requires installing all of its prerequisites first, and the entire dependency chain is resolved and validated at the configuration layer rather than failing only at runtime.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This is not an argument that “we are better than LangChain or Dify.” They perform very well in the scenarios they target. It is a practical record of what to do when the abstraction boundaries of mainstream frameworks do not align with your product requirements.&lt;/p&gt;
&lt;p&gt;The answer is: do not force your needs into them. Build your own. But when you do, be clear that you are making trade-offs, not inventing something from nothing.&lt;/p&gt;
</content:encoded></item><item><title>First Impressions of Obsidian-YOLO</title><link>https://xnnehang.top/en/posts/obsidian-yolo/</link><guid isPermaLink="true">https://xnnehang.top/en/posts/obsidian-yolo/</guid><description>A hands-on introduction to using the Obsidian-YOLO plugin and why it is worth recommending.</description><pubDate>Thu, 18 Jun 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I have been getting a little tired of writing blog posts in Obsidian lately. After switching to the Fuwari blog theme ([[Fuwari Blog Theme Guide]]), my local blogging syntax needs quite a few changes to become Fuwari-theme syntax. Image references also need to be handled. I often finish writing and simply throw away the source file, but YOLO, which I came across these past few days, happened to solve that problem for me.&lt;/p&gt;
&lt;p&gt;The project source is here:&lt;/p&gt;
&lt;p&gt;::github{repo=&quot;Lapis0x0/obsidian-yolo&quot;}&lt;/p&gt;
&lt;p&gt;The good news is that its author is an active maintainer, and PRs move very quickly.&lt;/p&gt;
&lt;h2&gt;Installation&lt;/h2&gt;
&lt;p&gt;You can install it directly from the plugin marketplace.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/img/obsidian-yolo/Pasted%20image%2020260618130052.png&quot; alt=&quot;Installing the YOLO plugin&quot; /&gt;&lt;/p&gt;
&lt;p&gt;As for why it is called YOLO, see the author’s post: &lt;a href=&quot;https://www.lapis.cafe/posts/ai-and-deep-learning/yolo/yolo-releasenote-01/&quot;&gt;YOLO Development Log (1): Why Develop YOLO?&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;Configuration Notes&lt;/h2&gt;
&lt;h3&gt;Provider Compatibility&lt;/h3&gt;
&lt;p&gt;Here are a few pitfalls when configuring a custom provider through newapi.&lt;/p&gt;
&lt;p&gt;I connected deepseek-v4-flash to NewAPI and then to YOLO. Along the way, I ran into these issues:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Without &lt;code&gt;/v1&lt;/code&gt;, newapi can retrieve the model list but does not actually reach the model itself, returning 200 directly. After this was fixed in a PR, it instead showed an empty-response error and prompted me to add &lt;code&gt;/v1&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Turning off reasoning passes &lt;code&gt;&quot;none&quot;&lt;/code&gt; to &lt;code&gt;&quot;thinking&quot;&lt;/code&gt;. I do not know whether newapi or deepseek-v4-flash is responsible, but it raised an error that the &lt;code&gt;&quot;thinking&quot;&lt;/code&gt; parameter list does not include &lt;code&gt;&quot;none&quot;&lt;/code&gt;. I also learned something from the author’s bot cat.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/img/obsidian-yolo/Pasted%20image%2020260618134726.png&quot; alt=&quot;Provider configuration screen&quot; /&gt;
&lt;img src=&quot;../../assets/img/obsidian-yolo/Pasted%20image%2020260618135345.png&quot; alt=&quot;Provider configuration screen 2&quot; /&gt;&lt;/p&gt;
&lt;p&gt;I did not expect even a cat to be better at reviewing code than I am.&lt;/p&gt;
&lt;p&gt;It pointed out that a default reasoning intensity should not stand in for disabling reasoning. That creates a semantic problem: if a provider does not support &lt;code&gt;none&lt;/code&gt;, it should be reused and given a supported way to disable reasoning. A model’s default reasoning intensity is usually low or medium, which conflicts with our intended meaning of “reasoning disabled.” The cat’s review was very sensible.&lt;/p&gt;
&lt;p&gt;Also, if you encounter an empty response, press Ctrl+Shift+I to inspect the Console output, and check whether &lt;code&gt;/v1&lt;/code&gt; has been added.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;If Ctrl+Shift+I does not respond, try going to &lt;code&gt;Settings -&amp;gt; Appearance -&amp;gt; Advanced -&amp;gt; Window frame style&lt;/code&gt;. Set it to “Obsidian style” and restart. After restarting, you will see the Obsidian icon in the upper-left corner. Click it -&amp;gt; View -&amp;gt; Toggle Developer Tools.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;Configuring Tool Calls&lt;/h3&gt;
&lt;p&gt;All tools appear enabled in the default Agent.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/img/obsidian-yolo/Pasted%20image%2020260618160903.png&quot; alt=&quot;Agent tool configuration&quot; /&gt;&lt;/p&gt;
&lt;p&gt;But when you talk to the Agent, you will find that it is not actually able to run terminal shell commands. You need to enable them again in the tools for &lt;code&gt;【Agent-Agents-Default (or a new Agent)】&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/img/obsidian-yolo/Pasted%20image%2020260618161202.png&quot; alt=&quot;Enabling Agent tools&quot; /&gt;&lt;/p&gt;
&lt;p&gt;You must also make sure the command being run is not on the denylist: &lt;code&gt;【Agent-Manage tools-Terminal commands-Configure】&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/img/obsidian-yolo/Pasted%20image%2020260618161405.png&quot; alt=&quot;Terminal command configuration&quot; /&gt;&lt;/p&gt;
&lt;p&gt;I also recommend writing it a Git skill and placing it in &lt;code&gt;YOLO/skills&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;Feature Experience&lt;/h2&gt;
&lt;h3&gt;Conversation Sidebar&lt;/h3&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/img/obsidian-yolo/Pasted%20image%2020260618162058.png&quot; alt=&quot;Conversation sidebar&quot; /&gt;&lt;/p&gt;
&lt;p&gt;The sidebar’s input state seems to include the current page’s blog post, line number, and surrounding content. It does not feel fragmented like a separate tool; instead, it is integrated quite well and feels very smooth to use. It can sometimes bring inspiration, and I can hand off chores like Git synchronization to it, avoiding the situation where I am too lazy to sync a repository manually and eventually lose data.&lt;/p&gt;
&lt;h3&gt;Quick Conversation Dialog&lt;/h3&gt;
&lt;p&gt;You can open a quick conversation dialog with &lt;code&gt;/&lt;/code&gt; + &lt;code&gt;Space&lt;/code&gt; to describe what you need, without taking your hands off the keyboard.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/img/obsidian-yolo/Pasted%20image%2020260618163233.png&quot; alt=&quot;Quick conversation dialog&quot; /&gt;&lt;/p&gt;
&lt;p&gt;The design philosophy behind this is beautiful, because frequently switching the right hand between mouse and keyboard can easily interrupt one’s train of thought.&lt;/p&gt;
&lt;h3&gt;Tab Completion&lt;/h3&gt;
&lt;p&gt;You can trigger automatic completion with symbols such as &lt;code&gt;，&lt;/code&gt;, &lt;code&gt;。&lt;/code&gt;, and &lt;code&gt;\n&lt;/code&gt; (a newline). The symbols can be added or removed, and after a configurable delay the LLM completion is triggered.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/img/obsidian-yolo/Pasted%20image%2020260618163412.png&quot; alt=&quot;Tab completion configuration&quot; /&gt;&lt;/p&gt;
&lt;p&gt;But perhaps my thought process is unusual: the model usually cannot keep up with it. For example, I may write down one idea while my mind has already jumped through three further associations, and the model is still on the first layer trying to guess what I will say next.&lt;/p&gt;
&lt;p&gt;And sometimes it does not reply at all. Next time I should turn on the Console and track it.&lt;/p&gt;
&lt;h3&gt;Memory System&lt;/h3&gt;
&lt;h4&gt;Markdown Source Memory Files&lt;/h4&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/img/obsidian-yolo/Pasted%20image%2020260618163928.png&quot; alt=&quot;Memory system interface&quot; /&gt;&lt;/p&gt;
&lt;p&gt;It records user preferences, and overall is similar to mem0. This kind of memory record has the advantage of making it easier to understand what the user needs; many things can be completed smoothly without being explicitly emphasized. But recording this kind of Memory alone cannot affect the model’s own reply style. Or rather, deliberately keeping the model’s style neutral, fair, calm, and without personality is the default.&lt;/p&gt;
&lt;p&gt;It is quite good as assistance, but I still prefer raising a cat with personality. This can be simulated by injecting personalized Skills, and the plugin itself does an excellent job supporting and building Skills.&lt;/p&gt;
&lt;h4&gt;RAG + Vector Database&lt;/h4&gt;
&lt;p&gt;This needs an embedding model. I do not have a suitable stable long-term API for now, and once a model is used to build the data, you generally have to keep using that model; otherwise, old and new data are incompatible because their dimensions differ.&lt;/p&gt;
&lt;p&gt;I have not used it yet.&lt;/p&gt;
&lt;h2&gt;Closing Thoughts&lt;/h2&gt;
&lt;p&gt;The experience has been good. At least when I wrote blog posts before, I had never experienced such an immersive Agent plugin. Overall, it feels very fresh.&lt;/p&gt;
&lt;p&gt;Although the Agent still cannot keep up with how my brain works, it is at least more diligent than I am. And it saves me from all the tedious things between writing a post and publishing it—uploading images to a submodule and maintaining two sets of syntax. YOLO has my back.&lt;/p&gt;
</content:encoded></item><item><title>How I Find Books</title><link>https://xnnehang.top/en/posts/my-book-finding-channels/</link><guid isPermaLink="true">https://xnnehang.top/en/posts/my-book-finding-channels/</guid><description>A few book-finding sites I use regularly: Z-Library, Anna&apos;s Archive, and Kox.moe.</description><pubDate>Sun, 14 Jun 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;Z-Library&lt;/h2&gt;
&lt;p&gt;https://zh.1lib.sk/&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/screenshots/zlibrary.jpg&quot; alt=&quot;Z-Library interface&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Most published books that are not too obscure can be found here, usually as EPUB, PDF, or MOBI files. I often use it to look for light novels, literature, reference books, and finished web novels, then read them on my Boox Leaf 2. As a result, I have bought very few books since college; I only buy physical copies of books I think I will reread and want to keep.&lt;/p&gt;
&lt;h2&gt;Anna&apos;s Archive&lt;/h2&gt;
&lt;p&gt;https://annas-archive.gl/&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/screenshots/%E5%AE%89%E5%A8%9C%E7%9A%84%E6%A1%A3%E6%A1%88.jpg&quot; alt=&quot;Anna&apos;s Archive interface&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Its domain seems to change often, so if it is unavailable, search Google for Anna&apos;s Archive. If you still cannot find it, it is probably keeping a low profile for a while.&lt;/p&gt;
&lt;p&gt;Its selection and file formats are much the same as Z-Library&apos;s, though it also seems to include a great deal of academic literature. I have not had much use for that myself. If a book is not on Z-Library, try here.&lt;/p&gt;
&lt;h2&gt;Kox.moe&lt;/h2&gt;
&lt;p&gt;https://kzo.moe/&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/screenshots/%E6%BC%AB%E7%94%BB_kox_moe.jpg&quot; alt=&quot;Kox.moe interface&quot; /&gt;&lt;/p&gt;
&lt;p&gt;A site dedicated entirely to manga.&lt;/p&gt;
&lt;p&gt;It appears to redirect between domains and requires registration and sign-in. It supports sending books to Kindle and offers EPUB and MOBI formats, but it does not support reading online.&lt;/p&gt;
</content:encoded></item><item><title>Things Pass Like Spring Dreams, Leaving No Trace; Yet Then, I Knew Only Joy.</title><link>https://xnnehang.top/en/posts/chongfu-zhi-le/</link><guid isPermaLink="true">https://xnnehang.top/en/posts/chongfu-zhi-le/</guid><description>From my mother&apos;s embroidery and my copying of classical Chinese to fishing in a game—repetitive activities hold something we cannot quite explain, yet know is there.</description><pubDate>Sat, 13 Jun 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;:::note[A Note from Korewaxnne]
This article draws one idea from three seemingly unrelated scenes—my mother embroidering, me copying passages of classical Chinese, and fishing in a game: when people perform repetitive activities, what they gain may be more than the result; it may be the calm that comes from the activity itself. The structure is light, progressing through three layers before arriving at &lt;em&gt;Six Records of a Floating Life&lt;/em&gt; and settling on the act of “recording.” If you, too, have ever had a repetitive habit that you could not explain but simply felt compelled to continue, perhaps this article can help you put that feeling into words.
:::&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Why did you suddenly feel like embroidering?&lt;/p&gt;
&lt;p&gt;(Silence...) I just wanted something to do to pass the time.&lt;/p&gt;
&lt;p&gt;I remember seeing you embroider all the time when I was little. Why don&apos;t I see any of it now?&lt;/p&gt;
&lt;p&gt;It&apos;s all hanging over there, in the room across the way.&lt;/p&gt;
&lt;p&gt;Oh... (Silence.)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;My mother and I had this conversation on Tuesday evening. It felt strangely familiar—or rather, her answer reminded me of myself. I watched her then, trying to detect the slightest wavering in the movement of her needle, but her hands remained fluid, without the faintest trace of hesitation.&lt;/p&gt;
&lt;p&gt;I asked because I had experienced something similar. In the months before the national college entrance examination, I became captivated by the feeling of copying classical Chinese prose into a notebook. &lt;em&gt;An Account of Wen Yuke&apos;s Painting of the Yundang Valley&apos;s Bent Bamboos&lt;/em&gt; and &lt;em&gt;An Account of the Xiangji Studio&lt;/em&gt; were my favorites; I copied each of them at least four or five times. I loved the sound that stirred inside me while I wrote. Perhaps it was a flutter of emotion, a sense of recognition—but more than that, it resembled the vague, indescribable feeling I had in my youth when reading, “I would buy osmanthus blossoms and take wine aboard, but it could never be like the journeys of my younger days.”&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Yet then, I knew only joy.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;After reading a modern translation of &lt;em&gt;Six Records of a Floating Life&lt;/em&gt;, I became even more determined to copy the book as my way of reading it. I copied “The Joys of the Wedding Chamber” and “The Little Pleasures of Life” several times. Classical Chinese moves too quickly when I merely read it; copying proceeds at exactly the right pace. Not that I was ever good at Chinese. I could never tune my mind to the same frequency as the teachers who wrote the model answers.&lt;/p&gt;
&lt;p&gt;I experienced something similar in &lt;em&gt;Red Dead Redemption 2&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;&amp;lt;iframe width=&quot;100%&quot; height=&quot;468&quot; src=&quot;//player.bilibili.com/player.html?bvid=BV1zU4y1474u&amp;amp;page=1&quot; frameborder=&quot;0&quot; allowfullscreen&amp;gt;&amp;lt;/iframe&amp;gt;&lt;/p&gt;
&lt;p&gt;At 5:35, Arthur takes little Jack fishing, and they have this conversation:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Fishing sure is boring, Uncle Arthur.&lt;/p&gt;
&lt;p&gt;Yeah, I know. Boring as hell. But then—something bites. You have food for days.&lt;/p&gt;
&lt;p&gt;Really?&lt;/p&gt;
&lt;p&gt;If you&apos;re lucky. But until then, you just sit and wait, and try not to think too much. It&apos;s good for you.&lt;/p&gt;
&lt;p&gt;It&apos;s good for you?&lt;/p&gt;
&lt;p&gt;I guess.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The state of mind behind those words was really the same as my mother&apos;s when she said she was “just passing the time,” and mine when I said, “Yet then, I knew only joy.”&lt;/p&gt;
&lt;p&gt;If we were to identify what these three activities have in common, they would share the following qualities:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;They take time without consuming much energy, and their repetition carries a certain rhythm—stitching through predetermined points again and again, waiting repeatedly for a fish to bite, copying one character after another.&lt;/li&gt;
&lt;li&gt;Their results are worth anticipating and may even have lasting benefits—the finished embroidery can be kept and admired again, the fish can provide food for days, and the completed copies can be revisited.&lt;/li&gt;
&lt;li&gt;They usually allow a person to enter a state of flow.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Let us use the opening of &lt;em&gt;Six Records of a Floating Life&lt;/em&gt; as our ending.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I was born on the twenty-second day of the eleventh month in winter, in the guiwei year of the Qianlong era. It was an age of peace and prosperity; I was born into a respectable family and lived beside the Canglang Pavilion in Suzhou. Heaven&apos;s generosity toward me could truly be called immense. Dongpo wrote, “Things pass like spring dreams, leaving no trace.” If I failed to preserve them in ink, I could hardly avoid betraying Heaven&apos;s great kindness. I reflected that “Guan Ju” stands at the head of the Three Hundred Odes, and so I placed husband and wife in the first record, with the rest following in order. I am ashamed that I neglected my studies in youth and know little more than the simplest characters. I have done no more than record true feelings and real events. To insist on scrutinizing the grammar would be to demand brightness from a tarnished mirror.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;For me, days without recording or copying really do feel as though “things pass like spring dreams, leaving no trace.” So I will make a small record of this feeling.&lt;/p&gt;
</content:encoded></item><item><title>In the LLM Era, What Exactly Is My Ability?</title><link>https://xnnehang.top/en/posts/what-is-my-ability-in-llm-era/</link><guid isPermaLink="true">https://xnnehang.top/en/posts/what-is-my-ability-in-llm-era/</guid><description>After a year of heavy AI coding use, my coding ability has nearly vanished. So what ability do I still have?</description><pubDate>Fri, 12 Jun 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I began relying heavily on AI coding in the GPT 5 era, entering the rabbit hole through an inexpensive team account on Linux.do. Later I encountered reverse proxies and connected GPT to Claude Code; the experience improved qualitatively.&lt;/p&gt;
&lt;p&gt;At the end of January 2026, I encountered openclaw and bought Claude Code Max around the same time—my first time using Claude. Claude 4.6 Opus changed my worldview.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/XnneHangLab/XnneHangLab/issues/260&quot;&gt;♻️ refactor(mcp): Discussion about Tool vs Skill vs Plugin.&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Claude and I completely refactored the architecture I had originally discussed with GPT. It felt like talking to a senior architect. That was the first time I experienced what it meant to “think with a model”—and using a model in place of thinking means allowing myself to leave thinking mode.&lt;/p&gt;
&lt;h2&gt;Yielding Code Review&lt;/h2&gt;
&lt;p&gt;After OpenClaw connected to GitHub, &lt;a href=&quot;https://github.com/xnne-bot&quot;&gt;Korewaxnne&lt;/a&gt; took over most of the work for me. At first, it only opened PRs and wrote PR messages—my pace of two or three PRs a day was disruptive for followers. I opened a new account to separate them, but a fixed workflow gradually formed: Claude Code writes the code → Korewaxnne opens a PR and reviews it → Claude Code revises it → I confirm CI is healthy, then LGTM and merge.&lt;/p&gt;
&lt;p&gt;For four whole months, I yielded code review. That laziness was serious: it meant that not even I could say I fully understood what my own project was made of, nor could I fully &lt;strong&gt;trust&lt;/strong&gt; it. A large volume of code was merged as long as it worked, had no static syntax errors, and passed unit tests. I even handed judgment at the feature level to AI.&lt;/p&gt;
&lt;p&gt;I gradually became the person who steers the direction of the project—but I was not an architect, because Claude Opus 4.6 designed even the architecture. I merely made choices.&lt;/p&gt;
&lt;p&gt;Sometimes I felt like a user, and chatting with Claude felt more like submitting requirements. For example, during the UI design of a knowledge graph, I said:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“This monochrome design is too dull right now. Plain orange feels a little tacky and easily makes me think of shit. I want it to be cuter, more cartoonish, and more playful.”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Claude Opus 4.6 understood my intent precisely and changed the design to an indigo inner core with dark-purple outer-ring accents. The palette was exactly to my taste.&lt;/p&gt;
&lt;p&gt;That kind of tolerance even deprived me of my &lt;strong&gt;ability to describe and express requirements properly&lt;/strong&gt;. Even if I am an unreasonable user, Claude seems able to accommodate me.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;[!NOTE]
What has degraded is not only coding: coding style, algorithmic foundations, architecture design, code review, prompt writing. Layer by layer, accommodation after accommodation has coddled me into a user embryo.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;If I had to write things by hand now, I could not even make sense of simple Paddle or PyTorch operators. That is already flattering myself.&lt;/p&gt;
&lt;h2&gt;Temporarily Leaving Claude&lt;/h2&gt;
&lt;p&gt;Claude was unavailable for two days, and those were the days that made me truly stop and think: what would I have left without it?&lt;/p&gt;
&lt;p&gt;Claude’s tolerance of me in every respect has made me spoiled. DeepSeek-V4-Pro likes making broad, irrelevant code changes, so I ruled it out immediately. GPT-5.5 is good at coding, but communicating with it feels like talking to cotton: no matter how I knead it, it calmly springs back to its original shape while soothing my emotions. Perhaps my prompts really are that bad.&lt;/p&gt;
&lt;p&gt;So if my coding ability is not enough to count as my ability, what should? A portfolio produced through Spec Coding? It cannot be, because as mentioned above, the absence of code review gradually loses both control over a project and the sense of trust in it.&lt;/p&gt;
&lt;p&gt;Perhaps this differs from person to person, but for me, &lt;strong&gt;the urge to express myself became the final protective charm of my bottom line&lt;/strong&gt;. I think &lt;strong&gt;thinking, and leaving traces behind&lt;/strong&gt;, is my real ability.&lt;/p&gt;
&lt;p&gt;[[After Building Long-Lived Systems: Is the RAG Monster Right for Constructing a Personal Blog Graph?]]&lt;/p&gt;
&lt;h2&gt;Where Are the Boundaries of Ability?&lt;/h2&gt;
&lt;p&gt;I do not plan to follow the algorithms path, so my thinking rarely goes deeply along the model itself. It focuses more on &lt;strong&gt;the capability boundaries of technology&lt;/strong&gt;: what a technology does well, what it does not, and under what conditions it fails.&lt;/p&gt;
&lt;p&gt;For RAG, for example, I focus on two fundamental limitations:&lt;/p&gt;
&lt;h3&gt;The Inarticulateness of Relationships&lt;/h3&gt;
&lt;p&gt;Vector similarity can connect two pieces of text, but even if the author themselves stands here, it is hard to say exactly what that connection is. Some relationship exists, but the meaning of the relationship itself cannot be expressed.&lt;/p&gt;
&lt;h3&gt;The Short-Sightedness of Relationships&lt;/h3&gt;
&lt;p&gt;After an article is chunked for input, each piece has only one or two hundred Chinese characters. The calculated relationships see only surface matches between small chunks, lacking deeper connections from the perspective of the full text. Many things are not written between the lines—for example, you may group &lt;em&gt;Norwegian Wood&lt;/em&gt; and &lt;em&gt;Three Days of Happiness&lt;/em&gt; together by feeling alone: loss, then recovery, then regret. But text-chunk similarity matching struggles to reflect that higher-level connection.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;[!NOTE]
How I define RAG’s capability boundary: it suits low-level association analysis built on a large volume of data—associations whose meaning is unknown, inarticulate, and impossible to explain clearly. It suits factual knowledge management, not analysis of emotionally felt texts. The latter cannot be taken out of context.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This way of defining boundaries is something I believe can be attributed to my ability. My core ability should be &lt;strong&gt;reflecting on, probing, and recording those boundaries while using things&lt;/strong&gt;. Large models usually only tell you, “this is the right way to do it.” But why specifically, why not another way, and what can be done—users do not care about those questions. Even if they do, after hearing a large model’s explanation and gaining a vague impression, they simply nod along.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;But confusion needs to be untangled, and feelings need to be examined and recorded deeply.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;After recording something, I usually talk someone’s ear off about it—normally my roommate, though perhaps I can brainwash Doubao with it in the future. When I get stuck or someone stumps me, I go back to revise and investigate further. That is probably the Feynman learning method: explain the dross to others, and keep the essence for yourself.&lt;/p&gt;
&lt;h2&gt;Unity of Knowing and Doing&lt;/h2&gt;
&lt;p&gt;In the LLM era, my coding ability can no longer count as my core ability. Situations that require a developer to investigate boundaries on the language side—such as the differences and trade-offs between &lt;code&gt;asyncio.to_thread&lt;/code&gt; and &lt;code&gt;threading&lt;/code&gt; in processes, CPU use, and memory allocation—will hardly appear again. This weakening is understandable. I only need to note down anything interesting I encounter—have AI write a memo so it will be easier to review next time.&lt;/p&gt;
&lt;p&gt;At the same time, prompt writing, context management, planning, and choosing Skills and tools count as necessary abilities, but they are still not the core. They can yield a great deal of usage experience and understanding of LLM boundaries—for example, how the Lost in the Middle phenomenon guides prompt writing, the attention-decay curve, and the causes of hallucination.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Code review&lt;/strong&gt; is different. The essence of review is not staring at bugs—large models can replace that labor—but a &lt;strong&gt;picky, almost obsessive sensibility&lt;/strong&gt; about project structure and code organization, a pursuit of better solutions. That is what I lack. &lt;a href=&quot;https://github.com/SigureMo&quot;&gt;SigureMo&lt;/a&gt; has always retained this habit. Their high-level fastidiousness and pursuit of elegance astonish and impress me. Perhaps opening a few PRs to a big shot now and then will let me learn something.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;[!NOTE]
AI has almost cut away the process of learning and coding. Someone with a weak coding foundation can maintain a frontend project—for example, I maintained two desktop projects without ever writing a line of Electron or Tauri code. Coding was skipped and time was left for thinking, but I often avoided thinking: I read novels while Claude wrote. The absence of thought made me doubt my own ability.&lt;/p&gt;
&lt;p&gt;The core ability as I see it is &lt;strong&gt;actively thinking, understanding, and leaving traces behind&lt;/strong&gt;—which, for me, means writing a blog.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Perhaps we should not judge personal ability in the future only from a project portfolio; we should also look at &lt;strong&gt;what someone truly understands and expresses&lt;/strong&gt;. In this respect, I admire &lt;a href=&quot;https://www.lapis.cafe/&quot;&gt;Shige&lt;/a&gt;. In my view, they have achieved &lt;strong&gt;the unity of knowing and doing&lt;/strong&gt;, which is also what I pursue.&lt;/p&gt;
&lt;p&gt;Why call it the unity of knowing and doing? We used to value learning first, then doing. Now it is different: do first, but truly understand what you did and why you did it—&lt;strong&gt;the weight of how you did it has fallen greatly&lt;/strong&gt;.&lt;/p&gt;
</content:encoded></item><item><title>After Building Long-Lived Systems: Is the RAG Monster Right for Constructing a Personal Blog Graph?</title><link>https://xnnehang.top/en/posts/rag-blog-graph/</link><guid isPermaLink="true">https://xnnehang.top/en/posts/rag-blog-graph/</guid><description>Starting from hands-on work on an AI desktop companion&apos;s long-term memory, this post compares three long-term-memory approaches for LLMs and asks whether RAG belongs in a personal blog&apos;s relationship graph.</description><pubDate>Sat, 06 Jun 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;My graduation project was about long-term companionship for an AI desktop companion. The main work was the desktop-companion system itself, but to retain memory across long contexts and separate conversations while keeping its persona from drifting, I also stitched together a long-term-memory module.&lt;/p&gt;
&lt;hr /&gt;
&lt;blockquote&gt;
&lt;p&gt;This section gets a little technical. I originally planned to analyze it across several posts with papers, but I lost those drafts, so this is only a concise outline of the main thread.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;Why External Memory?&lt;/h2&gt;
&lt;p&gt;Why do we need &lt;strong&gt;external&lt;/strong&gt; long-term memory in the first place? The GPT, Claude, and DeepSeek models we use today are fundamentally &lt;strong&gt;stateless inference&lt;/strong&gt; systems: an LLM receives all context for an input at once, then produces one output. Different LLMs have different context-window limits, usually somewhere between 200K and 1M tokens. And a context window is not the same as &lt;em&gt;effective context&lt;/em&gt;: performance can decline and hallucinations can appear before the stated limit, or, as the U-shaped curve in [[Attention Is Limited — Lost in the Middle]] shows, a large model can “forget the middle.”&lt;/p&gt;
&lt;p&gt;So whether the goal is remembering things after starting a fresh context or slowing that performance decline, a memory system is necessary. It needs to be &lt;strong&gt;external&lt;/strong&gt; to avoid taking up context, so it can be inserted only when needed to guide the model.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;I lost my earlier architecture analysis because of [[When My Cloud Provider Disappeared: Rethinking the Shape of a Personal Blog and What Is Worth Recording]]. So here is a brief look at the main kinds of long-term memory used by LLMs today.&lt;/p&gt;
&lt;h2&gt;Three Memory Approaches&lt;/h2&gt;
&lt;h3&gt;Approach One: Let the LLM Manage Markdown Reads and Writes Itself (OpenClaw)&lt;/h3&gt;
&lt;p&gt;::github{repo=&quot;zilliztech/memsearch&quot;}&lt;/p&gt;
&lt;p&gt;MemSearch is a representative project; OpenClaw uses it, or at least works on the same principle.&lt;/p&gt;
&lt;p&gt;It manages core information such as an Agent’s behavior, memory nodes, self-understanding, and user preferences through files like Agent.md, Memory.md, Identity.md, and User.md. Every file is read and written as Markdown.&lt;/p&gt;
&lt;p&gt;:::note&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Source files are &lt;strong&gt;directly readable&lt;/strong&gt; and maintainable by people.&lt;/li&gt;
&lt;li&gt;It avoids the overhead and complexity of an additional embedding model or database.&lt;/li&gt;
&lt;li&gt;It is &lt;strong&gt;very effective&lt;/strong&gt; for controlling preferences and writing style.
:::&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;:::warning&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The full files are generally injected only at startup. Over a long context, the persona gradually &lt;strong&gt;drifts or resets&lt;/strong&gt; to the LLM’s default style.&lt;/li&gt;
&lt;li&gt;The timing of reads and writes—the trigger conditions—is uncontrollable. Trigger rates are low and depend heavily on the LLM’s own capability. Claude performs relatively well.&lt;/li&gt;
&lt;li&gt;It is unsuitable for factual records across long timelines: the more it records, the more likely it is to &lt;strong&gt;dilute&lt;/strong&gt; what originally mattered in the prompt.
:::&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Approach Two: RAG-Based Vectorization and Similarity Matching (Mem0)&lt;/h3&gt;
&lt;p&gt;::github{repo=&quot;mem0ai/mem0&quot;}&lt;/p&gt;
&lt;p&gt;It captures conversation data produced by the user and LLM in real time, then uses an LLM to extract useful information, for example:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;User: The long-term memory system in my desktop-companion graduation project has been really hard to build lately.
LLM: XXXXXX
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It might extract two memories: “The user’s graduation project includes a long-term memory system” and “The user finds their graduation project difficult.”&lt;/p&gt;
&lt;p&gt;You can define the format and content of that extraction through prompts.&lt;/p&gt;
&lt;p&gt;Those memories are then &lt;strong&gt;vectorized&lt;/strong&gt; and stored in a database. Whenever the user asks something new, the system compares the question vector with vectors in the database, selects the top &lt;em&gt;n&lt;/em&gt;, and inserts them as context to support the LLM’s reply.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Write on a question; inject on a question.&lt;/strong&gt; Memory grows like a snowball.&lt;/p&gt;
&lt;p&gt;There are also mechanisms such as forgetting and reordering, but they are outside the scope of this discussion.&lt;/p&gt;
&lt;p&gt;:::note&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;External and &lt;strong&gt;insensitive to sequence&lt;/strong&gt;, which makes it well suited to long-term factual records.
:::&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;:::warning&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;It depends on embedding as an additional step and therefore needs another model.&lt;/li&gt;
&lt;li&gt;Stored vectors are &lt;strong&gt;not human-readable&lt;/strong&gt;; their direction is uncontrollable and cannot be corrected directly.&lt;/li&gt;
&lt;li&gt;The bar for writing is low, so people usually need repeated cleanup to maintain quality.&lt;/li&gt;
&lt;li&gt;It remembers facts, but does not truly have a soul (&lt;strong&gt;it is hard to influence the persona&lt;/strong&gt;).
:::&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Approach Three: Have Multiple Agents Continuously Organize and Consolidate Markdown (MemU)&lt;/h3&gt;
&lt;p&gt;::github{repo=&quot;NevaMind-AI/memU&quot;}&lt;/p&gt;
&lt;p&gt;I have not used this one in practice, but I have looked into it.&lt;/p&gt;
&lt;p&gt;Put simply, it uses an LLM’s own understanding in place of semantic matching through an embedding model.&lt;/p&gt;
&lt;p&gt;A conversation Agent handles the conversation, while a separate group of &lt;strong&gt;memory Agents&lt;/strong&gt; extracts memories, structures metadata, and builds an association graph. These memory Agents do not work only while a conversation is happening. Their highlight is that, even when nothing is being said, they keep traversing, retrieving, forgetting, and optimizing the existing memory structure almost like sleepwalking. &lt;em&gt;Like people consolidating memories through sleep.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Its final output includes human-readable Markdown source files, an association graph, metadata, and more.&lt;/p&gt;
&lt;p&gt;It leads Mem0 in several public benchmarks, but I ultimately did not choose it.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/img/covers/memu-benchmark.png&quot; alt=&quot;MemU benchmark comparison with other memory systems&quot; /&gt;&lt;/p&gt;
&lt;p&gt;:::note&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Memories are readable, and the structure is &lt;strong&gt;far more elegant&lt;/strong&gt; than the flat structure used by something like MemSearch.&lt;/li&gt;
&lt;li&gt;There is no embedding black-box layer in the middle.
:::&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;:::warning&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Retrieval is not especially fast. More memories do not make it faster; it &lt;strong&gt;cannot be parallelized&lt;/strong&gt; and is constrained by the retrieval LLM’s own reading and summarization speed.&lt;/li&gt;
&lt;li&gt;Token consumption is high. Memory Agents are demanding about model choice, so speed, understanding, context length, and price all need to be balanced. Claude Haiku and DeepSeek-V4-Flash are good choices.&lt;/li&gt;
&lt;li&gt;The more memory data exceeds the LLM’s context window, the &lt;strong&gt;worse the performance&lt;/strong&gt; becomes.
:::&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Is RAG Suitable for a Personal Blog System?&lt;/h2&gt;
&lt;p&gt;This question arose because my blog’s content used to be messy, and simple categories and tags were not enough to summarize or distinguish it. More importantly, they made it hard to show the relationships between posts.&lt;/p&gt;
&lt;p&gt;When I was first learning RAG, I wondered: could it uncover those relationships?&lt;/p&gt;
&lt;p&gt;::github{repo=&quot;Lapis0x0/obsidian-yolo&quot;}&lt;/p&gt;
&lt;p&gt;This project does exactly that. Its author is &lt;a href=&quot;https://www.lapis.cafe/&quot;&gt;Shige&lt;/a&gt;, who has also discussed the project extensively.&lt;/p&gt;
&lt;p&gt;But from the standpoint of its purpose, can it really serve as an internal presentation layer for a blog system?&lt;/p&gt;
&lt;h3&gt;The Limits of Vector Similarity&lt;/h3&gt;
&lt;p&gt;Based on what we have discussed above, RAG builds connections through retrieval similarity, whether vector semantic matching, keyword matching, or hybrid retrieval. Setting aside the complexity of computation and additional models, it ultimately returns a connection from one text chunk in an article to another text chunk in a different article. That connection &lt;em&gt;does not say what kind of relationship it is&lt;/em&gt;; mathematically, it only means those two chunks are more related than a chosen threshold.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Unlike extracting useful memories from conversation and converting them into vectors, blogs need to be processed through text chunking: each post is divided into chunks of a certain size and then converted into vectors.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;So what we get is a relationship between a particular text chunk in one article and a particular text chunk in another—a relationship no one knows, and perhaps even the author cannot explain. The key point is that &lt;strong&gt;the relationship still cannot be clearly named.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;That means the problem troubling me remains unresolved: I still cannot both classify my blog clearly and manage and present the relationships between different posts. Other people would still think my blog’s content organization is a mess.&lt;/p&gt;
&lt;p&gt;RAG creates a huge number of messy relationship links between posts, but cannot explain those relationships.&lt;/p&gt;
&lt;h3&gt;The Short-Sightedness of Text Chunking&lt;/h3&gt;
&lt;p&gt;At the same time, those relationship links themselves are &lt;strong&gt;short-sighted&lt;/strong&gt;. Why? The issue lies in text chunking. It limits relationship analysis to a small paragraph, or even a single sentence. But authors usually want a &lt;em&gt;global view&lt;/em&gt; of a relationship, like thematic reading, or perhaps only a &lt;em&gt;feeling&lt;/em&gt;. That feeling or global view is something RAG cannot express. Even when it can, it is drowned out by the many low-level connections it calculates.&lt;/p&gt;
&lt;p&gt;At least for now, RAG itself is unsuitable for directly presenting the relationship graph of personal blog content.&lt;/p&gt;
&lt;h3&gt;An Alternative: a Citation Graph&lt;/h3&gt;
&lt;p&gt;If you want to show associations between blog posts, use a citation graph.&lt;/p&gt;
&lt;p&gt;If article A cites article B, or vice versa, then A and B are connected.&lt;/p&gt;
&lt;p&gt;Such a graph may not be very deep, but it reflects a direct relationship. And that direct relationship is supplied by the author, so it is persuasive. Generating this kind of graph is simple; it does not require masses of annotations even on the edges between nodes.&lt;/p&gt;
&lt;p&gt;Putting the complete citation chain of an article at the end can also communicate useful information and guide readers onward.&lt;/p&gt;
&lt;h3&gt;Where Should RAG Be Used?&lt;/h3&gt;
&lt;p&gt;It is not suited to a blog system’s public presentation, but it is a useful companion for building a personal knowledge base, just as it is in YOLO.&lt;/p&gt;
&lt;p&gt;A blog system only needs to show what its author wants readers to see: categories, tags, series, shelves, and a graph of related citations.&lt;/p&gt;
&lt;p&gt;RAG, on the other hand, can help the author discover possible connections within their articles—connections that may be difficult even for the author to explain. Gradually turning those connections into explainable, clearly articulated themes is the author’s work.&lt;/p&gt;
&lt;p&gt;So, &lt;strong&gt;a blog system is prepared by the author for readers, while RAG is prepared for the author&lt;/strong&gt;. It may guide what the author writes next.&lt;/p&gt;
&lt;p&gt;There is also one point that is easy to overlook: RAG needs data volume. With only a few dozen posts, it yields little. Once a blog reaches hundreds or thousands of posts, its value rises substantially, because those obscure connections become clearer and converge rather than remaining isolated.&lt;/p&gt;
&lt;p&gt;In short, RAG is for insightful, prolific bloggers—not for a lazy pigeon like me, who writes only in fits and starts.&lt;/p&gt;
</content:encoded></item><item><title>When My Cloud Provider Disappeared: Rethinking the Shape of a Personal Blog and What Is Worth Recording</title><link>https://xnnehang.top/en/posts/cloud-service-provider/</link><guid isPermaLink="true">https://xnnehang.top/en/posts/cloud-service-provider/</guid><description>Rethinking the shape of a blog and what it should record after a cloud provider&apos;s disappearance caused data loss.</description><pubDate>Mon, 01 Jun 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;As the title says: at the end of May, the cloud provider hosting my blog system, Fox Cloud, disappeared. Without warning, it shut down and destroyed a batch of cloud-server instances, and mine happened to be among them.&lt;/p&gt;
&lt;p&gt;I had not been paying much attention to my blog lately, so I had not backed it up in advance. Then, at the end of March, water got into my laptop and burned out its drive. Between the two, I lost quite a lot of blog archives. Those posts had never been pushed to GitHub; I wrote them locally and uploaded them directly to the blog system. So I lost both the goodnight and her.&lt;/p&gt;
&lt;p&gt;The only material I have recovered from backups reaches March 2025, and the newest post is [[On Mortal Lives in Renegade Immortal and A Record of a Mortal&apos;s Journey to Immortality]]. But now that I think about it, I actually felt relieved, because that was the last review-like thing I wrote in a calm state of mind.&lt;/p&gt;
&lt;p&gt;I once wrote that days spent without recording what I had watched or read seem, once they pass, to have disappeared completely without a trace.&lt;/p&gt;
&lt;p&gt;This past year felt like that. What did I write afterward? [[Attention Is Limited — Lost in the Middle]], [[Single Image Does Not Equal Multiple Images: Why VLMs Hallucinate More with Multiple Images, and a Two-Stage Fix|Single image ≠ multiple images]]. But before discussing what deserves to be recorded, let us first look back at the shapes a personal blog can take.&lt;/p&gt;
&lt;h1&gt;Forms of a Blog&lt;/h1&gt;
&lt;h2&gt;Depending on a Cloud Platform&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://www.cnblogs.com/Reisentyan&quot;&gt;Cnblogs — Moon Rabbit&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/img/covers/blog-platform-cnblogs.png&quot; alt=&quot;Cnblogs interface&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Cnblogs is excellent in both appearance and freedom; it is far, far better than a certain CS platform.&lt;/p&gt;
&lt;p&gt;But in terms of its form, the articles it presents live on the platform, while archives usually depend on users&apos; own backups. Local data and platform data do not synchronize automatically. Synchronizing across devices is troublesome and requires some intermediary device or cloud platform. And if the device holding the archive suddenly fails, the backup cannot quickly be restored and synchronized from the cloud to local storage.&lt;/p&gt;
&lt;p&gt;There is also the question of whether the platform itself will survive. There were earlier moments when Cnblogs seemed close to shutting down.&lt;/p&gt;
&lt;p&gt;And with better-run CSDN, I do not think you want people to see jumping advertisements beside what you wrote, paid-unlock prompts suddenly appearing below it, or a requirement to log in before reading the full text.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;I have posted only a single &lt;code&gt;.condarc&lt;/code&gt; on CSDN. Yet its reading experience—finding an article with something useful in it, only to discover that it was copied from Cnblogs or another platform—and its habit of appearing near the top of search results have made me feel much worse about cloud platforms.&lt;/p&gt;
&lt;h2&gt;Depending on a Personal Cloud Server&lt;/h2&gt;
&lt;p&gt;I used this approach for more than two years.&lt;/p&gt;
&lt;p&gt;The first system I deployed was NBlog: https://naccl.top/&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/img/covers/blog-platform-nblog.png&quot; alt=&quot;NBlog interface&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Later I deployed Shiroi: https://innei.in/&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/img/covers/blog-platform-shiroi.png&quot; alt=&quot;Shiroi interface&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Both separate their frontend from their backend. That introduces a modest barrier: CORS, running frontend and backend separately, and potentially difficult setup when no suitable Docker image exists—especially for frameworks one does not already know.&lt;/p&gt;
&lt;p&gt;They share the same problem as Cnblogs:&lt;/p&gt;
&lt;p&gt;The source data kept in an archive and the data uploaded into the blog system are not fully the same, and converting between them is difficult. It is hard to restore local data into blog form by re-uploading posts one by one, and it is hard to restore blog-form data back into a local backup.&lt;/p&gt;
&lt;p&gt;The latter, Shiroi, supports importing and exporting all posts. It can export existing blog data from the same blogging system and import it again, which is somewhat useful when migrating servers. But it is inherently incompatible with other blogging systems, and its archive files are not human-readable, so they cannot serve as local archives. That makes the feature rather awkward. Perhaps because of that awkwardness, its import system also had a few bugs and was not backward-compatible with old versions; I was forced to restore every post by hand. During the major React security incident in 2025, my blog was affected and I had to reinstall the system, but a backup exported from the old version could not be parsed or imported by the new one =-=. The two versions were only about half a year apart.&lt;/p&gt;
&lt;p&gt;:::warning
Besides server costs, the most frightening part of maintaining a personal blog is being betrayed by a provider that disappears. Lost data is simply lost; there may be no way to retrieve it. Because of the React incident, I temporarily moved from Tencent Cloud to Fox Cloud, but afterward the difficulty of migrating kept me from moving back. Building Shiroi was genuinely not easy, and after restoring the data I had no energy left for an additional backup. Each problem fed into the next.
:::&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;While using these kinds of blogs, I would usually also push the blog to some GitHub repository as an archive. But my habit of pushing was terrible: sometimes I had not finished writing and had to wait; sometimes I felt it was not worth pushing; sometimes a GitHub token expired and, after putting it off, I forgot. Sometimes I organized files into folders by year and month; other times I forgot to create a month folder, so several months of files were squeezed into one.&lt;/p&gt;
&lt;p&gt;The management was exhausting even for me to look at. But I could not simply delete the repository. Even after repeated reorganizations, entropy increased with continued use. And the largest problem was that, to make cloning faster, posts and images lived in separate repositories, with images referenced through jsDelivr URLs uploaded by PicGo. That made the image repository even more frightening.&lt;/p&gt;
&lt;h2&gt;Depending on GitHub Pages and Workflow Deployment&lt;/h2&gt;
&lt;p&gt;https://xnnehang.top/&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/img/covers/blog-platform-current.png&quot; alt=&quot;Current blog interface&quot; /&gt;&lt;/p&gt;
&lt;p&gt;This blog is built directly by a workflow from a GitHub project and pushed to GitHub Pages.&lt;/p&gt;
&lt;p&gt;::github{repo=&quot;MrXnneHang/xnnehang.top&quot;}&lt;/p&gt;
&lt;p&gt;It has several advantages:&lt;/p&gt;
&lt;p&gt;:::tip&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;You can pull the whole project at any time. It contains all blog source data, planned clearly and named sensibly, in Markdown—the same format in which a user originally wrote it. It remains usable whether for migration or reading.&lt;/li&gt;
&lt;li&gt;It does not require complicated frontend or backend deployment. Only a domain and DNS are needed; once configured, all building and updating are handled automatically by the workflow.&lt;/li&gt;
&lt;li&gt;The project is the blog. Every update is archived immediately; synchronization is a backup, unless GitHub disappears or the policies for Pages or workflows change.
:::&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;p&gt;For me, its most important benefit is that it eliminates the Blog and Blog_Image repositories where I had always maintained bad update habits.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/SigureMo&quot;&gt;SigureMo&lt;/a&gt; used this approach from the start. I remember adding their friendship link during my NBlog era; if I had discovered it earlier, I would have taken many fewer detours.&lt;/p&gt;
&lt;p&gt;This blog is simple enough that I can focus more on writing it without worrying about when to commit and push.&lt;/p&gt;
&lt;p&gt;I remember that after moving to Shiroi, although the blog system became much prettier and more complex, I actually wrote less often. That was a pity.&lt;/p&gt;
&lt;h1&gt;What Is Worth Recording&lt;/h1&gt;
&lt;p&gt;This is different from the expression of feelings and emotions in reviews.&lt;/p&gt;
&lt;p&gt;When it comes to technical or tutorial-like blog posts produced while learning—and I say “while” because I have a habit of learning as I write, which is exciting, whereas summaries after I have learned everything are instead dull—much of the material is basic and even contains many mistakes. I tend to make a hypothesis, test it, and revise it as I go. By the time I correct my thinking, I may have missed correcting the material already written.&lt;/p&gt;
&lt;p&gt;I once asked my natural-language-processing teacher whether he wrote blog posts, because the way he taught often felt like the thought process of writing a blog post—and like me, he could very easily wander off-topic. He said that he had written for several years but later stopped.&lt;/p&gt;
&lt;p&gt;When I asked why, he said that looking back, many of his early articles were wrong, naïve, and insufficiently deep. Following the principle of not spreading errors, he stopped writing.&lt;/p&gt;
&lt;p&gt;That is true. Looking at my earlier guides to using uv or my PyQt study diary from where I am now, these posts that especially emphasize starting from zero are really far too basic for me. They offer no benefit and even contain many awkward expressions.&lt;/p&gt;
&lt;p&gt;Just imagining a beginner happening upon them and being misled by my distorted reading of the official documentation, or someone skilled in the subject reading my beginner&apos;s diary, makes me so embarrassed that I want to disappear into the ground.&lt;/p&gt;
&lt;p&gt;I used to avoid reading such posts. This time, losing the archive let me escape from them, and I felt relieved instead.&lt;/p&gt;
&lt;p&gt;I have to reflect: should posts like those still be written? Should they be published to public spaces without review?&lt;/p&gt;
&lt;p&gt;Learning as I write leaves a deeper impression on me, whether what I learn is right or wrong, and the process of correction makes my understanding deeper still. But before claiming I have truly understood something correctly, I should let a language model review it.&lt;/p&gt;
&lt;p&gt;Here I will also divide the things worth recording into a few broad categories.&lt;/p&gt;
&lt;p&gt;:::note&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Resources&lt;/strong&gt; usually do not involve transmitting specific knowledge or reflections. They simply recommend channels, applications, or information to other people—for example, sites for finding books or manga.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Reviews&lt;/strong&gt; are still worth building as both display cases for memories and traps for like-minded people.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Tutorials&lt;/strong&gt; are process-oriented records, such as a guide to using an application or a piece of software: launching SKSE for &lt;em&gt;The Elder Scrolls V: Skyrim&lt;/em&gt;, refreshing animation data, adjusting body shapes, sorting mods, and so on.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Reflections&lt;/strong&gt; are deeper thoughts produced by an event or an object. They may address an object&apos;s essence directly, or connect it with other things and then reveal a general pattern or arrive at a personal conclusion. They do not have to be clearly right or wrong, but they must make sense to me.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Learning as I Build&lt;/strong&gt; should carry a &lt;code&gt;useless&lt;/code&gt; tag: an exploratory process with little nutritional value. If readers truly cannot find a suitable tutorial or example, perhaps they can find what they need in my exploration, or arrive at a conclusion that makes sense to me. Of course, that conclusion need not be right; it only needs to be coherent. I will let an LLM review whether it is right or wrong.
:::&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>Single Image Does Not Equal Multiple Images: Why VLMs Hallucinate More with Multiple Images, and a Two-Stage Fix</title><link>https://xnnehang.top/en/posts/multi-image-vlm/</link><guid isPermaLink="true">https://xnnehang.top/en/posts/multi-image-vlm/</guid><description>An investigation into why web and API results diverge during multi-image analysis, from Lost in the Middle to a two-stage approach based on per-image pre-summaries.</description><pubDate>Sun, 08 Feb 2026 00:00:00 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;A short summary because this article is rather long: it began when I found that multi-image analysis on the web and through an API produced very inconsistent results. I worked through the reasons for that gap step by step, then tried to find an engineering-level remedy.&lt;/p&gt;
&lt;p&gt;The method is simple. I am putting it here in the hope that it saves someone else some confusion and time.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;Background&lt;/h2&gt;
&lt;p&gt;A few weeks ago, I had a course project about battery defect detection and automatic sorting. We had fewer than ten battery samples, and the defects were mainly missing outer wrapping. With so few samples, I did not think we could train a conventional model that distinguished defects, whether by image classification, YOLO, or anything else.&lt;/p&gt;
&lt;p&gt;The recommended approach for the project was edge detection with OpenCV. I was not very familiar with OpenCV, and its typing caused me pain, so I thought of using YOLO to locate the batteries and their coordinates. A bounding box can locate the center point; rotate it 45° clockwise and counter-clockwise and compare the aspect ratio to determine the battery&apos;s orientation and approximate angle. That makes it easier to determine the grasp position and gripper angle. Then a VLM—Vision-Language Model, or multimodal model—could decide whether the battery was defective and what kind of defect it had.&lt;/p&gt;
&lt;p&gt;At first, I uploaded several groups of battery images under different lighting conditions to ChatGPT and Gemini. They achieved an astonishing 100% accuracy during recognition and inspection, and their replies were highly consistent across attempts. This held even when I uploaded six or seven images at once, including one intact battery as a reference while defects were described in the prompt. I thought: wow, a week-long course project is going to take one morning.&lt;/p&gt;
&lt;p&gt;So I downloaded a batch of VLMs through Ollama for local deployment and testing, partly to increase the “workload,” and partly for lower latency.&lt;/p&gt;
&lt;h3&gt;The reversal: a huge gap between the web app and direct API calls&lt;/h3&gt;
&lt;p&gt;But testing changed everything. I could not tell whether the model failed to understand my prompt or the images I sent. This time, both accuracy and consistency were very low—accuracy was around 50%, and it often contradicted itself. My batteries had only two labels, so I thought: wow, it is just making things up.&lt;/p&gt;
&lt;p&gt;But when I sent a single image to a VLM for description, the gap from ChatGPT on the web was not visibly that large. For both single-image and multi-image requests, I put the images into this structure:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;OpenAIMessage(
  role=&quot;user&quot;,
  content=[
    {&quot;type&quot;: &quot;text&quot;, &quot;text&quot;: &quot;user_prompt&quot;},
    {&quot;type&quot;: &quot;image_url&quot;, &quot;image_url&quot;: &quot;data:image/png;base64,iVBORw...&quot;},
    ...(images)
  ]
)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;At that point, I thought the model difference might really be the issue, so I tested API calls with models such as gemini-flash-2.5 and chatgpt-5.1-chat. But even with the same model, its accuracy differed greatly from what I got on the web. Once the number of images exceeded four, consistency also began to decline.&lt;/p&gt;
&lt;p&gt;After a little research, I found that this looked very similar to the long-context retrieval and positional-bias problem described by &lt;em&gt;Lost in the Middle&lt;/em&gt;. The large difference between web and API performance may be because:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The web app may perform &lt;strong&gt;per-image pre-summarization, reranking, or selective feeding&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;The web app may have &lt;strong&gt;stronger system prompts and output constraints&lt;/strong&gt;, such as forcing JSON or a response for each image.&lt;/li&gt;
&lt;li&gt;API-side parameters—temperature, max output, tool choice, and concurrency order—may also affect consistency.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Multi-image understanding is not single-image understanding&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://arxiv.org/html/2407.15272&quot;&gt;MIBench: Evaluating Multimodal Large Language Models over Multiple Images&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://aclanthology.org/2025.acl-long.214.pdf&quot;&gt;Towards Text-Image Interleaved Retrieval&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://arxiv.org/abc/2408.02718&quot;&gt;MMIU: Multimodal Multi-image Understanding for Evaluating Large Vision-Language Models&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://arxiv.org/html/2406.12742v1&quot;&gt;Benchmarking Multi-Image Understanding in Vision and Language Models&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Multi-image benchmarks such as MIBench, MMIU, and MIRB consistently show that models experience substantial performance drops and struggle with relational understanding when moving from one image to many. Some work also explicitly points out the engineering bottleneck of &lt;strong&gt;too many visual tokens&lt;/strong&gt; in multimodal settings, which makes compression necessary.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;[!WARNING]
One reasonable mechanistic explanation is that when visual tokens from several images and text enter the same Transformer context, they amplify long-context retrieval difficulty and positional bias—for example, the finding in &lt;em&gt;Lost in the Middle&lt;/em&gt; that information in the middle is harder to use. [This is only my speculation.]&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;How models receive &lt;code&gt;image_url&lt;/code&gt; (base64) and reason over it&lt;/h2&gt;
&lt;p&gt;The papers can be a little hard to parse, but they all keep talking about too many tokens. What I was actually curious about was how the tokens for text and an &lt;code&gt;image_url&lt;/code&gt; relate to one another after a message enters the model, and how they might be separated. Do they simply get concatenated, or do multimodal models reason over images and text differently?&lt;/p&gt;
&lt;h3&gt;A base64 image is not reasoned over directly&lt;/h3&gt;
&lt;p&gt;Using base64 for an &lt;code&gt;image_url&lt;/code&gt; is merely convenient for HTTP transport. During inference, the model decodes the base64 into an image. In other words, a VLM actually sees the user prompt plus the image.&lt;/p&gt;
&lt;h3&gt;How images are resized and counted as tokens&lt;/h3&gt;
&lt;p&gt;See OpenAI&apos;s &lt;a href=&quot;https://platform.openai.com/docs/guides/images-vision&quot;&gt;Calculating costs&lt;/a&gt; documentation.&lt;/p&gt;
&lt;h4&gt;Tile-based models (gpt-4o / gpt-4.1 / gpt-4.5, and so on)&lt;/h4&gt;
&lt;p&gt;&lt;code&gt;detail=&quot;low&quot;&lt;/code&gt; uses a fixed base-token cost. For &lt;code&gt;detail=&quot;high&quot;&lt;/code&gt;, the image is first resized proportionally so that its longest side is at most 2048 and its shortest side is 768, then charged by the number of 512×512 tiles: &lt;code&gt;tokens = base + tile_tokens × tiles&lt;/code&gt;.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Model family&lt;/th&gt;
&lt;th&gt;Unit&lt;/th&gt;
&lt;th&gt;Unit size&lt;/th&gt;
&lt;th&gt;Per-unit cost&lt;/th&gt;
&lt;th&gt;Fixed cost&lt;/th&gt;
&lt;th&gt;Total formula&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Tile-based (gpt-4o/4.1/4.5)&lt;/td&gt;
&lt;td&gt;tile&lt;/td&gt;
&lt;td&gt;512×512&lt;/td&gt;
&lt;td&gt;170 tokens/tile&lt;/td&gt;
&lt;td&gt;85 tokens/image&lt;/td&gt;
&lt;td&gt;high: 85 + 170×tiles, low: 85&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Patch-based (gpt-4.1-mini)&lt;/td&gt;
&lt;td&gt;patch&lt;/td&gt;
&lt;td&gt;32×32&lt;/td&gt;
&lt;td&gt;≈1.62 tokens/patch&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;patches=ceil(w/32)×ceil(h/32); if &amp;gt;1536, downscale; tokens=ceil(patches×1.62)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Model&lt;/th&gt;
&lt;th&gt;Input dimensions&lt;/th&gt;
&lt;th&gt;detail&lt;/th&gt;
&lt;th&gt;Tiles/patches&lt;/th&gt;
&lt;th&gt;Calculation&lt;/th&gt;
&lt;th&gt;Final tokens&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;gpt-4o&lt;/td&gt;
&lt;td&gt;1024×1024&lt;/td&gt;
&lt;td&gt;low&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;td&gt;= 85&lt;/td&gt;
&lt;td&gt;85&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;gpt-4o&lt;/td&gt;
&lt;td&gt;1024×1024&lt;/td&gt;
&lt;td&gt;high&lt;/td&gt;
&lt;td&gt;resized to 768×768, tiles=2×2=4&lt;/td&gt;
&lt;td&gt;= 85+170×4=765&lt;/td&gt;
&lt;td&gt;765&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;gpt-4o&lt;/td&gt;
&lt;td&gt;2048×4096&lt;/td&gt;
&lt;td&gt;high&lt;/td&gt;
&lt;td&gt;resized to 768×1536, tiles=2×3=6&lt;/td&gt;
&lt;td&gt;= 85+170×6=1105&lt;/td&gt;
&lt;td&gt;1105&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;gpt-4.1-mini&lt;/td&gt;
&lt;td&gt;1024×1024&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;td&gt;patches=32×32=1024&lt;/td&gt;
&lt;td&gt;= ceil(1024×1.62)=1659&lt;/td&gt;
&lt;td&gt;1659&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;gpt-4.1-mini&lt;/td&gt;
&lt;td&gt;1800×2400&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;td&gt;resized patches=1452&lt;/td&gt;
&lt;td&gt;= ceil(1452×1.62)=2353&lt;/td&gt;
&lt;td&gt;2353&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3&gt;How pixels become vision tokens&lt;/h3&gt;
&lt;p&gt;OpenAI does not publish this. The following are approaches used by some open-source VLMs:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/img/covers/vlm-token-to-vision.png&quot; alt=&quot;Image to token&quot; /&gt;&lt;/p&gt;
&lt;h3&gt;How vision tokens are concatenated with or isolated from prompt tokens&lt;/h3&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/img/covers/vlm-concatenation.png&quot; alt=&quot;Concatenation approach&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/img/covers/vlm-cross-attention.png&quot; alt=&quot;Cross-attention injection&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/img/covers/vlm-bottleneck-query.png&quot; alt=&quot;Query bottleneck&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Concatenation&lt;/strong&gt; is the simplest, end-to-end approach: let the LLM decide for itself. But visual tokens consume context length, and attention is more easily diluted with multiple images. It faces the same problem as long context: attention is not only diluted, but unevenly so; it also accelerates context growth.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Cross-attention&lt;/strong&gt; treats vision as external memory that text queries on demand. It is easier to control the “visual-information budget” in engineering terms and better suited to long sequences and multiple images, but it adds modules and training complexity. Query uncertainty makes it hard to know whether the model actually saw a particular image. Its essential problem is therefore similar to the previous approach: there, a model may selectively ignore an image; here, the image may never be queried.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Query bottlenecks&lt;/strong&gt;: I do not understand them well enough yet…&lt;/p&gt;
&lt;h2&gt;Difficulties in real applications&lt;/h2&gt;
&lt;p&gt;Multi-image tasks are difficult in practice. First, the &lt;strong&gt;number&lt;/strong&gt; of images is uncertain; second, the &lt;strong&gt;relationships&lt;/strong&gt; between them are uncertain; third, the images, the user&apos;s specific multi-image task, and their references are uncertain. Every one of these tests token limits and attention allocation.&lt;/p&gt;
&lt;p&gt;:::note
&lt;strong&gt;Three uncertainties&lt;/strong&gt;: uncertain quantity → diluted attention; uncertain relationships → hard for the model to match coupled images; uncertain task → the model tends to focus only on the most recent instruction rather than the global context.
:::&lt;/p&gt;
&lt;h3&gt;Uncertain quantity&lt;/h3&gt;
&lt;p&gt;A user might send more than ten images and blow up the token budget, assuming the request does not exceed the input/output limit. With more images, less attention goes to each one, and we do not know how it is allocated. Some images may not be “attended to” at all.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Multiple images split attention, and in a real application we do not know how many images will compete for it. The design should therefore accommodate any acceptable input count.&lt;/strong&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;[!CAUTION]
Of course, VLM reasoning alone cannot achieve this today. As the battery-detection retest below shows, images beyond a single request&apos;s token limit are simply truncated.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;Uncertain relationships&lt;/h3&gt;
&lt;p&gt;For example, an indecisive user may submit many character images—two images of each character—and ask us to compare them and choose the one they prefer. The image pairs are highly coupled. A model may realize that these pairwise relationships exist, but not know which images form the pairs. With more images, it is unlikely to match every similar character at once.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Sometimes images are coupled. We want to guide the model to notice that coupling instead of dropping everything in a pile and asking it to figure it out.&lt;/strong&gt;&lt;/p&gt;
&lt;h3&gt;Uncertain specific tasks&lt;/h3&gt;
&lt;p&gt;Often, the task is not written directly in the current message; it must be inferred from the entire context. For example, while role-playing:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;U: &quot;Don&apos;t you dislike mushrooms?&quot;
A: &quot;Yes. If you dare put any in the soup, I will show you what regret means.&quot;
U: &quot;Then look at this: [an image of food being cooked, with many ingredients including mushrooms]&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Often the &lt;strong&gt;puzzle&lt;/strong&gt; is not stated outright, such as “find the mushrooms in the image.” More commonly, the models I encounter do not connect their reply to the whole context very much. They put nearly all their attention weight on the latest user instruction—something like “describe this” or “look at this”—then start describing the entire scene at length. That may be a learned preference. It is not the response we ideally want: “Hm? I think I see mushrooms. You put mushrooms in it, didn&apos;t you? You did, right?”&lt;/p&gt;
&lt;h2&gt;How to respond&lt;/h2&gt;
&lt;p&gt;There is a rather simple solution to the uncertainties of quantity, relationships, and user needs. It does not alter the model&apos;s inference; it can be layered onto an application. Split image analysis and text analysis into two real stages.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/img/covers/vlm-per-image-analysis.png&quot; alt=&quot;Per-image analysis&quot; /&gt;&lt;/p&gt;
&lt;p&gt;The branch for per-image analysis is separate for token-budget reasons, so it should be designed as an optional switch.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Stage one&lt;/strong&gt; uses only a vision model to analyze each image and extract its concrete information. At this point, do not supply the user&apos;s latest prompt. Extract the analysis from its context, give the vision model only a system prompt and a fixed extraction instruction as its user prompt, and aim for JSON like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;{
  &quot;scene&quot;: &quot;VS Code full-screen with code and a terminal&quot;,
  &quot;key_items&quot;: [
    {
      &quot;type&quot;: &quot;app&quot;,
      &quot;label&quot;: &quot;VS Code&quot;,
      &quot;detail&quot;: &quot;dark theme, full-screen window&quot;
    },
    {
      &quot;type&quot;: &quot;ui&quot;,
      &quot;label&quot;: &quot;file tree&quot;,
      &quot;detail&quot;: &quot;multiple directories expanded in the left explorer&quot;
    },
    {
      &quot;type&quot;: &quot;code&quot;,
      &quot;label&quot;: &quot;Python code&quot;,
      &quot;detail&quot;: &quot;async-related functions shown in the central editor&quot;
    }
  ],
  &quot;visible_text&quot;: [&quot;run_tool_loop&quot;, &quot;ToolTrace&quot;, &quot;vision__screen_shot&quot;],
  &quot;ui_hints&quot;: [&quot;multiple file tabs at the top&quot;, &quot;terminal logs at the bottom&quot;],
  &quot;uncertainty&quot;: [&quot;some file names are too small to read in full&quot;]
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Extract features from each image independently and concurrently, then combine the results into a list or dictionary when complete.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Stage two&lt;/strong&gt; places the combined vision summaries together with the user prompt:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[User Prompt]
...
[Vision Summaries]
{&quot;p1&quot;: ..., &quot;p2&quot;: ...}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Ideally, also send all original images to the LLM together—provided there are not too many, perhaps fewer than five. If there are more than ten, sending them will not help anyway.&lt;/p&gt;
&lt;p&gt;There is also much we can do between the two stages: use a JSON key to distinguish or couple images, for example.&lt;/p&gt;
&lt;h3&gt;Advantages&lt;/h3&gt;
&lt;p&gt;:::tip&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;It does not care how many images arrive. In theory, even twenty or thirty can be processed. The JSON can directly guide the model&apos;s visual understanding.&lt;/li&gt;
&lt;li&gt;We can customize JSON keys through prompts to create coupling or separation and clarify image relationships.&lt;/li&gt;
&lt;li&gt;It turns a seemingly heavier and harder multi-image analysis task into a text-understanding task that can rely on text for its answer. Images occupy less of the context and text more, allowing the model to work with language and making it more likely to attend to the entire context.
:::&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Disadvantages&lt;/h3&gt;
&lt;p&gt;:::caution&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Expensive&lt;/strong&gt;—not just a little expensive. Every image needs its own extraction pass, then all images may be sent again for the multi-image pass. The improvement becomes more obvious with more images; for one or two images, there is little reason to do this. It should not be the default method, but an option users can enable.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Slow&lt;/strong&gt;—even with concurrency, it adds at least one response round compared with direct conversation.
:::&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Battery-detection retest&lt;/h2&gt;
&lt;p&gt;The setup used ten images: really five images duplicated once. Each test sent one more image than the previous one. The tested model was &lt;code&gt;gpt-5.1-2025-11-13&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;Send image content directly to the model&lt;/h3&gt;
&lt;p&gt;Test code:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;from __future__ import annotations
import base64
from openai import OpenAI


def image_to_base64(path: str) -&amp;gt; str:
    with open(path, &quot;rb&quot;) as f:
        return base64.b64encode(f.read()).decode(&quot;utf-8&quot;)


image_paths = [&quot;pic/1.jpg&quot;, &quot;pic/2.jpg&quot;, ..., &quot;pic/10.jpg&quot;]

for i in range(10):
    image_contents = []
    for path in image_paths[: i + 1]:
        image_contents.append(
            {
                &quot;type&quot;: &quot;image_url&quot;,
                &quot;image_url&quot;: {&quot;url&quot;: f&quot;data:image/jpeg;base64,{image_to_base64(path)}&quot;},
            }
        )
    response = client.chat.completions.create(
        model=model_name,
        messages=[{&quot;role&quot;: &quot;user&quot;, &quot;content&quot;: [{&quot;type&quot;: &quot;text&quot;, &quot;text&quot;: prompt_text}, *image_contents]}],
        temperature=0,
    )
    print(f&quot;Number of input images: {i + 1}&quot;)
    print(response.choices[0].message.content)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Output:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Ground truth: p1 intact p2 intact p3 damaged p4 intact p5 damaged p6 intact p7 intact p8 damaged p9 intact p10 damaged
Input images: 1  p1 intact
Input images: 2  p1 intact p2 intact
Input images: 3  p1 intact p2 intact p3 damaged
Input images: 4  p1 intact p2 intact p3 damaged p4 damaged
Input images: 5  p1 intact p2 intact p3 damaged p4 intact p5 damaged
Input images: 6  p1 intact p2 intact p3 damaged p4 damaged p5 damaged
Input images: 7  p1 intact p2 intact
Input images: 8  p1 intact p2 intact p3 damaged
Input images: 9  p1 intact p2 intact p3 damaged p4 damaged
Input images: 10 p1 intact p2 intact p3 damaged p4 damaged p5 damaged
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As you can see, consistency started becoming a problem after more than three images. With five inputs, it happened to guess all of them correctly. But beyond five, the model did not reply about the other images at all. I suspect they were truncated because the single-request input-token limit was exceeded.&lt;/p&gt;
&lt;h3&gt;Apply a map-reduce approach&lt;/h3&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/img/covers/multi-image-5input.jpeg&quot; alt=&quot;5 input&quot; /&gt;
&lt;img src=&quot;../../assets/img/covers/multi-image-10input.jpeg&quot; alt=&quot;10 input&quot; /&gt;&lt;/p&gt;
&lt;p&gt;For it, this task consists of independent items, so the number of items and image truncation do not have much impact. Of course, truncation remains painful for tasks that require relationships between images.&lt;/p&gt;
&lt;p&gt;There is also a substantial issue with token consumption and overly fast context growth. Concurrent single-image processing is already expensive. Combining the outputs into the original context makes that context grow very quickly, bringing the long-context attention bottleneck earlier.&lt;/p&gt;
&lt;h3&gt;The prompt I use&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;You are a &quot;Vision Extractor&quot; responsible for extracting facts and evidence relevant to the user&apos;s question from input images.
You do not need to write the final natural-language answer; another chat model will produce the final conversational response.
Your goal is to use concise, reusable, machine-consumable structured output to accurately describe the information in the images that is relevant to the question, and to state uncertainty explicitly.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The complete prompt includes an explanation of the inputs, five key principles—describe only what is visible, support downstream reasoning, focus on what is relevant to the question, control length and density, and handle private information—and strict requirements for JSON output.&lt;/p&gt;
&lt;h3&gt;Performance on relational tasks&lt;/h3&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/img/covers/multi-image-related-task-1.jpeg&quot; alt=&quot;Related task 1&quot; /&gt;
&lt;img src=&quot;../../assets/img/covers/multi-image-related-task-2.jpeg&quot; alt=&quot;Related task 2&quot; /&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;It looks as though I did a poor job with &lt;code&gt;send_text&lt;/code&gt;, or perhaps truncating by character count made the layout look awful. Another point: &lt;code&gt;gpt-5.1-2025-11-13&lt;/code&gt; replies rather stiffly. Version 5.2 costs far more. I generally use vision fallback: the &lt;code&gt;vision model&lt;/code&gt; is called only when looking at images, generates summaries, and passes them to a chat model. That lets me choose a chat model with more human warmth, while also deciding whether to send it the summaries together with the images.&lt;/p&gt;
&lt;/blockquote&gt;
</content:encoded></item><item><title>Termix: A Very Cool Web-Based SSH Client</title><link>https://xnnehang.top/en/posts/termix-web-ssh-guide/</link><guid isPermaLink="true">https://xnnehang.top/en/posts/termix-web-ssh-guide/</guid><description>A Termix deployment guide: use Docker to host a web-based SSH client and finally say goodbye to Termius acting up.</description><pubDate>Mon, 29 Dec 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;Preface&lt;/h2&gt;
&lt;p&gt;A few days ago, my roommate showed me a Termius-like application deployed on the web. I was amazed: it is very full-featured, supports SFTP with both uploads and downloads, closely copies the Termius visual design, and can run on a local port for browser access.&lt;/p&gt;
&lt;p&gt;Repository:&lt;/p&gt;
&lt;p&gt;https://github.com/Termix-SSH/Termix&lt;/p&gt;
&lt;p&gt;Deploying it publicly brings several conveniences:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;When changing to a new device or operating system, you do not need to struggle with installing software or look up IP addresses and passwords again.&lt;/li&gt;
&lt;li&gt;You can use someone else&apos;s device without leaving traces behind.&lt;/li&gt;
&lt;li&gt;Most importantly, you do not have to worry about Termius occasionally going rogue and uninstalling itself.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I have used the SSH connection in BaoTa Panel and Termius. No need to mention the one bundled with the cloud provider; I am sick of scanning QR codes for Tencent Cloud servers.&lt;/p&gt;
&lt;p&gt;At first, Termius feels beautifully designed. I could spend half a day playing with terminal-style choices alone, and its UI elements are modern, elegant, and pleasant to look at. That is why I kept using it. But as mentioned above, it sometimes goes rogue and uninstalls itself, clearing every cache in the process, so every machine has to be imported again.&lt;/p&gt;
&lt;p&gt;Of course, there is a paradox here. If the server hosting my Termix has an internal error and Termix stops working, I still need Termius to connect. There is no escaping that.&lt;/p&gt;
&lt;p&gt;A case of liking the new and abandoning the old.&lt;/p&gt;
&lt;p&gt;Let us start deploying it.&lt;/p&gt;
&lt;h2&gt;A very simple local deployment&lt;/h2&gt;
&lt;p&gt;If you have used Docker and Docker Compose before, deployment is very easy. If not, wait a moment while I briefly cover installing Docker and Docker Compose.&lt;/p&gt;
&lt;h3&gt;Preparation: installing Docker and Docker Compose&lt;/h3&gt;
&lt;p&gt;First, install some required packages:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;If the system is too old, you can upgrade it with &lt;code&gt;apt upgrade&lt;/code&gt;, although for a new machine I recommend reinstalling directly.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code&gt;apt update
apt install curl vim wget gnupg dpkg apt-transport-https lsb-release ca-certificates
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then add Docker&apos;s GPG public key and APT repository:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;curl -sSL https://download.docker.com/linux/debian/gpg | gpg --dearmor &amp;gt; /usr/share/keyrings/docker-ce.gpg
echo &quot;deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-ce.gpg] https://download.docker.com/linux/debian $(lsb_release -sc) stable&quot; &amp;gt; /etc/apt/sources.list.d/docker.list
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For machines in mainland China, you can use the Tsinghua TUNA mirror:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;curl -sS https://download.docker.com/linux/debian/gpg | gpg --dearmor &amp;gt; /usr/share/keyrings/docker-ce.gpg
echo &quot;deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-ce.gpg] https://mirrors.tuna.tsinghua.edu.cn/docker-ce/linux/debian $(lsb_release -sc) stable&quot; &amp;gt; /etc/apt/sources.list.d/docker.list
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Update the package list, then install Docker CE:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;apt install docker-ce docker-ce-cli containerd.io
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We can install the latest Docker Compose version directly from Docker&apos;s official GitHub release:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;curl -L https://github.com/docker/compose/releases/latest/download/docker-compose-Linux-x86_64 &amp;gt; /usr/local/bin/docker-compose
chmod +x /usr/local/bin/docker-compose
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can now run &lt;code&gt;docker-compose version&lt;/code&gt; to confirm that it installed successfully.&lt;/p&gt;
&lt;h3&gt;Deployment&lt;/h3&gt;
&lt;p&gt;In a directory where you want to keep it, for example &lt;code&gt;/opt/termix&lt;/code&gt;, create &lt;code&gt;compose.yml&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;services:
  termix:
    image: ghcr.io/lukegus/termix:latest
    container_name: termix
    restart: unless-stopped
    ports:
      - &apos;8080:8080&apos;
    volumes:
      - termix-data:/app/data
    environment:
      PORT: &apos;8080&apos;

volumes:
  termix-data:
    driver: local
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then pull the image:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;root@ser351791695801:/opt/termix# docker compose pull
[+] pull 19/19
 ✔ Image ghcr.io/lukegus/termix:latest Pulled
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Finally, run the image:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;root@ser351791695801:/opt/termix# docker compose up
[+] up 3/3
 ✔ Network termix_default    Created
 ✔ Volume termix_termix-data Created
 ✔ Container termix          Created
Attaching to termix
termix  | Configuring web UI to run on port: 8080
termix  | SSL disabled - using HTTP-only configuration (default)
termix  | Starting nginx...
termix  | Starting backend services...
termix  | [7:35:12 AM] [INFO] Termix Backend starting - Version: 1.9.0
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If no errors appear, press Ctrl+C to stop it, then run it in the background:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;root@ser351791695801:/opt/termix# docker compose up -d
[+] up 1/1
 ✔ Container termix Running
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The application will then stay alive when the terminal closes.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I was curious why some people write &lt;code&gt;compose.yml&lt;/code&gt;, some write &lt;code&gt;compose.yaml&lt;/code&gt;, and some write &lt;code&gt;docker-compose.yml&lt;/code&gt;. They all seem to be recognized by &lt;code&gt;docker compose pull&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Gemini reminded me that it searches for them automatically according to a priority order:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/img/covers/202512291042933.png&quot; alt=&quot;Compose-file lookup order&quot; /&gt;&lt;/p&gt;
&lt;p&gt;This also avoids conflicts when there is more than one Compose file.&lt;/p&gt;
&lt;h2&gt;Public deployment&lt;/h2&gt;
&lt;p&gt;Here I will only demonstrate the approach I use most often: a 1Panel reverse proxy.&lt;/p&gt;
&lt;p&gt;1Panel installation: https://1panel.cn/&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Install OpenResty from the 1Panel app store.&lt;/li&gt;
&lt;li&gt;Create a DNS A record that points to the server&apos;s public IP address.&lt;/li&gt;
&lt;li&gt;Create a reverse-proxy website for &lt;code&gt;127.0.0.1:8080&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Apply for a certificate, which requires binding a DNS account.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/img/covers/202512291043494.png&quot; alt=&quot;Add a DNS account&quot; /&gt;&lt;/p&gt;
&lt;p&gt;When applying for the certificate, select the option to skip DNS verification:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/img/covers/202512291043854.png&quot; alt=&quot;Apply for a certificate&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Finally, enable HTTPS for the site and select the certificate for the corresponding domain:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/img/covers/202512291043299.png&quot; alt=&quot;Enable HTTPS&quot; /&gt;&lt;/p&gt;
&lt;p&gt;The only thing to remember is to &lt;strong&gt;save&lt;/strong&gt;.&lt;/p&gt;
&lt;h2&gt;Screenshots&lt;/h2&gt;
&lt;p&gt;After that, you can access it directly from the public internet.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/img/covers/202512291044412.png&quot; alt=&quot;Sign-in screen&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/img/covers/202512291055872.png&quot; alt=&quot;System information panel&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/img/covers/202512291055842.png&quot; alt=&quot;Terminal&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/img/covers/202512291057168.png&quot; alt=&quot;SFTP&quot; /&gt;&lt;/p&gt;
&lt;p&gt;It is worth trying, and I really like this UI too. A visual-design enthusiast is here.&lt;/p&gt;
&lt;p&gt;See you next time =-=//&lt;/p&gt;
</content:encoded></item><item><title>Bringing AI Chat to Congyin in Chill with You: Lo-Fi Story</title><link>https://xnnehang.top/en/posts/cong-yin-ai-chat/</link><guid isPermaLink="true">https://xnnehang.top/en/posts/cong-yin-ai-chat/</guid><description>Notes from exploring a mod that adds AI chat to Congyin, the protagonist of the Steam Pomodoro game Chill with You: Lo-Fi Story.</description><pubDate>Sat, 15 Nov 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I am very fond of Pomodoro timers.&lt;/p&gt;
&lt;p&gt;That is how I came across this game on Steam:&lt;/p&gt;
&lt;h2&gt;The Game&lt;/h2&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/img/covers/202601061008735.png&quot; alt=&quot;Chill with You: Lo-Fi Story&quot; /&gt;&lt;/p&gt;
&lt;p&gt;At heart, it is a game that combines a Pomodoro timer, to-do list, notes, calendar statistics, lo-fi music, collectibles, and character customization.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/img/covers/202601061011430.png&quot; alt=&quot;Game window&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Before this, I had always used something similar: Spirit City.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/img/covers/202601061013417.png&quot; alt=&quot;Spirit City: Lofi Sessions&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/img/covers/202601061015872.png&quot; alt=&quot;Spirit City game window&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Unlike Spirit City, though, &lt;em&gt;Chill with You&lt;/em&gt; includes a small mechanic for interacting with its character. Its premise is that the player is on a video call with Congyin, much like sharing a study room. As time passes, you gradually unlock her story, and, like a visual novel, it unfolds through choices. I do not yet know whether there is a romance route later on.&lt;/p&gt;
&lt;p&gt;[Could add some screenshots here if I come across them.]&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/img/covers/202601061025541.png&quot; alt=&quot;She is annoyed when teased during a focus session&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Spirit City, by contrast, invites the player to imagine themself as the character on screen.&lt;/p&gt;
&lt;p&gt;If I had to compare them, I unquestionably prefer the Japanese-inspired character design in &lt;em&gt;Chill with You&lt;/em&gt;. Congyin also has Japanese voice acting. What is intriguing is that her voice has a slightly mechanical quality, almost like AI-generated speech. It makes me feel as if I am studying with a cyber girlfriend, and that AI-like feeling only makes me like it more.&lt;/p&gt;
&lt;p&gt;The game also has a mug motif that feels remarkably suited to me. Through Congyin, the author mentions having become dehydrated during an intense stretch of creative work. Since then, she has paid close attention to choosing mugs she likes, so that she will take a sip whenever she is writing. As for me, I make tea before starting a Pomodoro session and drink it while I work; other drinks lack that same sense of ritual. In this respect, the author feels like another version of me somewhere in the world.&lt;/p&gt;
&lt;p&gt;Still, when it comes to music, I prefer Spirit City. I have listened to it for dozens of hours without tiring of it, and hearing it immediately helps me settle down. The musical selections in &lt;em&gt;Chill with You&lt;/em&gt; do not feel as “deep” as Spirit City’s. They are a little too light to draw me into a deeper flow state—perhaps I simply have not listened to them long enough.&lt;/p&gt;
&lt;h2&gt;The Mod&lt;/h2&gt;
&lt;p&gt;Love really is the first driving force of creation. Or perhaps lust is?&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/img/covers/202601061029269.png&quot; alt=&quot;Steam review&quot; /&gt;&lt;/p&gt;
&lt;p&gt;::github{repo=&quot;qzrs777/AIChat&quot;}&lt;/p&gt;
&lt;h2&gt;In Action&lt;/h2&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/img/covers/202601100432475.png&quot; alt=&quot;Freely chatting with Congyin&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/img/covers/202601100438203.png&quot; alt=&quot;The moonlight is beautiful tonight&quot; /&gt;&lt;/p&gt;
&lt;p&gt;While she speaks, the character’s mouth moves with the volume of her voice. The movement is subtle, though, so it does not seem to have shown up in any of my screenshots.&lt;/p&gt;
&lt;p&gt;The character also reacts while speaking: she may look at you, keep doing what she was doing, or seemingly drink water, among other things.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/img/covers/202601100443124.png&quot; alt=&quot;Drinking water&quot; /&gt;&lt;/p&gt;
</content:encoded></item><item><title>What Bad Intentions Could I Possibly Have?</title><link>https://xnnehang.top/en/posts/wo-neng-you-shenme-huai-xinsi-ne/</link><guid isPermaLink="true">https://xnnehang.top/en/posts/wo-neng-you-shenme-huai-xinsi-ne/</guid><description>In my anxiety on the train back to campus, an animal&apos;s perspective gave me a good dream.</description><pubDate>Sun, 07 Sep 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;img src=&quot;../../assets/img/wo-neng-you-shenme-huai-xinsi-ne/PixPin_2026-08-08_23-04-37.jpg&quot; alt=&quot;What Bad Intentions Could I Possibly Have?&quot; /&gt;&lt;/p&gt;
&lt;p&gt;I read this while feeling restless on the train back to campus. The start of term made me anxious, but I could not explain exactly what I was anxious about.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I did not realize then that it was my last long break at university.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Picking up this book at random helped me out of that difficulty. It gave me the perspective of other creatures. It was as though I were the cat in the book, looking at humans and at everything I was facing. Suddenly, I understood how tiny all the things worrying me really were. Page forty-nine gave me a good dream—perhaps only ten-odd minutes long—on the high-speed train. Once the anxiety came undone, I closed my eyes in relief and quickly slipped into REM sleep.&lt;/p&gt;
&lt;p&gt;I cannot remember the dream clearly. I remember that &lt;em&gt;Siddhartha&lt;/em&gt;, or perhaps &lt;em&gt;The Razor&apos;s Edge&lt;/em&gt;, describes a yogi using meditation to transcend their spirit and inhabit other objects. This book gave me a similar opening and perspective. In several places, it truly let me observe the world and humanity from a bird&apos;s point of view.&lt;/p&gt;
&lt;p&gt;Thank you for those few pages.&lt;/p&gt;
</content:encoded></item><item><title>Attention Is Limited — Lost in the Middle</title><link>https://xnnehang.top/en/posts/attention-is-limited/</link><guid isPermaLink="true">https://xnnehang.top/en/posts/attention-is-limited/</guid><description>LLM attention is limited. Starting from the difference in weighting between system and user prompts, this article explores the Lost in the Middle phenomenon and what it can teach us.</description><pubDate>Sun, 06 Jul 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Yesterday, I suggested that someone place repeatedly inserted knowledge-base content and memories in the user prompt rather than the system prompt.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/AlfreScarlet/MoeChat/issues/4#issuecomment-3104493088&quot;&gt;❇️ A small suggestion: use user prompts instead of system prompts to insert World Info and diary entries. #4&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I raised two properties of the system prompt: it is &lt;strong&gt;globally visible and highly weighted&lt;/strong&gt;, so conflicts can cause the model to hallucinate. A user prompt, by contrast, is &lt;strong&gt;local, with more recent content receiving greater attention weight&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;At the time, those claims came from experience and my trust in Gemini 2.5 Pro.&lt;/p&gt;
&lt;p&gt;But they deserve a more evidence-based analysis.&lt;/p&gt;
&lt;p&gt;First, &lt;strong&gt;locality and the greater attention paid to recent content are actually properties of both system prompts and user prompts&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;One part of my view was somewhat mistaken: I thought system prompts inserted later would always receive less attention than the initial prompt. (That is not really how it works. Attention is greatest at the beginning and near the end, and lighter everywhere else; see Lost in the Middle below.)&lt;/p&gt;
&lt;p&gt;Put simply, we can view an LLM as a Transformer with an extremely long context. It distinguishes System Prompts from User Prompts through special tokens such as (&lt;code&gt;&amp;lt;|system|&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;|user|&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;|assistant|&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;|startoftext|&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;|endoftext|&amp;gt;&lt;/code&gt;), and training probably teaches it to distinguish different roles in this way. The system role also seems to carry additional penalties and constraints, which makes it appear more important.&lt;/p&gt;
&lt;p&gt;On subsequent inputs, we still feed the entire context window back into the model. The reason the first system prompt remains well remembered even after a long conversation is explained below.&lt;/p&gt;
&lt;h2&gt;Lost in the Middle&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://arxiv.org/abs/2307.03172&quot;&gt;Lost in the Middle: How Language Models Use Long Contexts&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This paper corrected one of my earlier misconceptions. I had thought that an LLM&apos;s attention always increased toward the most recent content. In reality, its attention distribution is U-shaped: it remembers the beginning and the end clearly, while becoming &lt;code&gt;Lost in the Middle&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;Argument:&lt;/h3&gt;
&lt;p&gt;The paper notes that we would like an LLM&apos;s attention to resemble an omniscient perspective, examining the entire context steadily and evenly. Yet the efficiency and robustness with which models use information from long contexts are questionable. The authors argue that when a model processes a long text, its performance can vary dramatically depending on &lt;strong&gt;where the relevant information appears within that text&lt;/strong&gt;.&lt;/p&gt;
&lt;h3&gt;Experiments:&lt;/h3&gt;
&lt;p&gt;The authors used two types of experiments:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Multi-document question answering&lt;/li&gt;
&lt;li&gt;Key-value retrieval&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;::github{repo=&quot;nelson-liu/lost-in-the-middle&quot;}&lt;/p&gt;
&lt;p&gt;They placed the relevant information at the beginning, middle, or end, then asked questions to evaluate how effectively the model used its context.&lt;/p&gt;
&lt;h3&gt;Conclusion:&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;A U-shaped performance curve:&lt;/strong&gt; Model performance follows a pronounced “U-shaped” curve. Models perform best when the relevant information appears at the &lt;strong&gt;beginning of the input (the primacy effect)&lt;/strong&gt; or at the &lt;strong&gt;end (the recency effect)&lt;/strong&gt;. Performance drops significantly when the relevant information appears in the &lt;strong&gt;middle&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Longer contexts lead to worse performance:&lt;/strong&gt; The study also found that even for models specifically designed to handle long contexts, overall performance falls substantially as the input grows longer.&lt;/p&gt;
&lt;h2&gt;An Interesting Phenomenon&lt;/h2&gt;
&lt;p&gt;Every model becomes less capable in a long context. More precisely, its ability to use relevant information declines. To put it simply, we can think of its &lt;strong&gt;attention as becoming diluted&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Suppose the U-shaped function remains fixed, with &lt;strong&gt;the area under the curve representing the total attention weight&lt;/strong&gt; and &lt;strong&gt;the horizontal axis representing entries in conversational order&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;The attention weight once shared by three chronological entries in a short conversation is now divided among six or even ten, leaving less for each one. The model therefore becomes worse at extracting &lt;strong&gt;the relevant information—understanding the question and the requirements&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Alternatively, suppose the U-shaped function changes while the attention assigned to the first three and most recent three entries remains the same. The U then becomes “steeper,” meaning that the model grows more forgetful: it remembers almost nothing from the middle, and its performance naturally declines.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A model always remembers the beginning and the present most clearly. In that respect, it resembles the way humans think.&lt;/strong&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;[!TIP]
Because special tokens may cause the system prompt to receive a greater share of the attention weight—which also makes it “globally visible” to some extent—we should allocate system-prompt space with particular care. We should value and make good use of a model&apos;s attention just as we do our own.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;[!NOTE]
&lt;strong&gt;Attention is limited.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;Addendum&lt;/h2&gt;
&lt;p&gt;I have found that &lt;strong&gt;proposing an idea and then correcting it step by step&lt;/strong&gt; gives me a much deeper and clearer understanding than simply accepting the correct answer. It also feels far more dependable than applying experience directly.&lt;/p&gt;
&lt;p&gt;This approach also seems to echo the Feynman technique. I had already noticed that I learn better when writing blog posts as I go. Later, however, I became overly dependent on LLMs, and most of what I wrote turned into records of how a problem was solved and which path led to the solution. I find that kind of chronological logging rather discouraging. Today, by contrast, I rediscovered the pleasure of keeping a record.&lt;/p&gt;
&lt;p&gt;When watching films or reading novels, I used to restrain myself from offering opinionated commentary. It was tiring, such opinions could wander endlessly, and everyone saw things differently, making it easy to draw attacks from people who disagreed.&lt;/p&gt;
&lt;p&gt;For questions with definite answers, however, having an opinion seems necessary. It pushes me to keep examining and revising my own view: is it correct, or might it mislead someone? It also makes me analyze the subject more deeply and perhaps correct my own thinking along the way.&lt;/p&gt;
&lt;p&gt;So I will give this article a Feynman-style ending: a visual explanation and a summary in simpler language.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/img/covers/attention-ushape-short.jpeg&quot; alt=&quot;U-shaped attention distribution in a short context&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/img/covers/attention-ushape-long.jpeg&quot; alt=&quot;U-shaped attention distribution in a long context&quot; /&gt;&lt;/p&gt;
&lt;p&gt;We use these two function plots as an analogy for how attention weight is distributed in a short context of twenty entries and a long context of forty. This is only an analogy: I cannot first prove that the distribution is symmetrical, and for now probably no one can quantify this capacity precisely, so we will not dwell on those issues.&lt;/p&gt;
&lt;p&gt;The model has the following initial assumptions:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Across the entire context window, the total attention—the maximum number of context tokens—remains constant. In other words, the integrals for twenty and forty entries are assumed to be equal. (They probably should not be equal, but let us assume they are.)&lt;/li&gt;
&lt;li&gt;The system prompt exerts a stronger constraint on the model because of penalties applied during training; it is the red line, while the user prompt is the blue line.&lt;/li&gt;
&lt;li&gt;Both follow a U-shaped distribution. The model assigns more attention weight at the beginning and end: Lost in the Middle.&lt;/li&gt;
&lt;li&gt;Under a long context, model performance—its ability to extract relevant information—gradually declines, producing lower y-values.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;No other properties of the functions in these plots should be taken literally. I cannot claim that they are symmetrical, nor can I prove that attention is lower at every point in a long context. So even if you notice those details, please pretend you did not.&lt;/p&gt;
&lt;p&gt;Even this simple model is enough to answer why knowledge-base content and diary entries should be repeatedly inserted through User Prompts to guide the next response.&lt;/p&gt;
&lt;p&gt;:::warning
&lt;strong&gt;Repeatedly inserting guidance into separate prompts lengthens the conversation context and thereby accelerates the decline in model performance.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;At the time, one user prompt was guided by three system prompts—core mem, long mem, and knowledge base—meaning that a single conversational exchange consumed four entries in the context window.
:::&lt;/p&gt;
&lt;p&gt;:::warning
&lt;strong&gt;To some extent, system prompts are more globally visible than user prompts, so conflicting instructions are more likely to cause model hallucinations.&lt;/strong&gt;
:::&lt;/p&gt;
</content:encoded></item><item><title>We Made a Beautiful Bouquet</title><link>https://xnnehang.top/en/posts/ruhuashuban-de-lianai/</link><guid isPermaLink="true">https://xnnehang.top/en/posts/ruhuashuban-de-lianai/</guid><description>A film about literary romance, surface-level compatibility, and the passage of time.</description><pubDate>Fri, 20 Jun 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;Being a literary youth is a disease&lt;/h2&gt;
&lt;p&gt;Being a literary youth is a disease that makes you awkward in a crowd—or an involuntary inability to fit in. It is not noble, of course. It may often make both you and the people around you uncomfortable.&lt;/p&gt;
&lt;p&gt;It usually also requires at least one unrealistic fantasy. When that fantasy falls apart, the relationship may be hard to sustain too. In the middle of the film, when the male lead decides to find a proper job, the atmosphere begins to change. I stepped back from the film there as well.&lt;/p&gt;
&lt;p&gt;Meeting someone similar is pleasant at first; living together is constrained; over the long term, it is unreasonable.&lt;/p&gt;
&lt;p&gt;Because if someone nearly identical to us existed, people would be most afraid of looking into the mirror—or of seeing themselves, or their former selves. When I see characters in a work who resemble me, I usually feel two things at once: surprise and embarrassment. Living with a perfectly identical version of myself probably would not feel very good either.&lt;/p&gt;
&lt;p&gt;But people who are entirely on the same wavelength do not actually exist. The female lead falls asleep watching gas tanks, and the male lead does not like mummies either—he is afraid the waiter will discover that he watches them. From the beginning, their supposed meeting of souls was only an assumption, like assuming they were listening to the same song. Like the metaphor they both say in unison five years later at the beginning:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;One person wears one earphone and the other wears the other. They appear to be listening to the same song, but they are actually hearing different songs.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I was very curious about what they felt when they stood and walked toward that couple, then saw each other.&lt;/p&gt;
&lt;h2&gt;A beginning is also the beginning of an ending&lt;/h2&gt;
&lt;p&gt;I especially liked a passage quoted somewhere in the film:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;A beginning is also the beginning of an ending. Meeting is always accompanied by parting. Love is like a banquet that must eventually end. People in love merely bring the things they like, sit facing one another across a table, chat, and make bitter amusement of it.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;In a straight-line pursuit, the moment when two balls come closest—or meet—is also the moment they start moving apart and can never meet again. The process of approaching makes the heart race, &lt;em&gt;dokidoki&lt;/em&gt;. After the meeting, the intense feeling may gradually fade. Perhaps that explains why romance always feels most beautiful in its ambiguous early stage: it is still in the process of drawing closer.&lt;/p&gt;
&lt;p&gt;A passage from Mishima&apos;s &lt;em&gt;Runaway Horses&lt;/em&gt; seems to complement this: once something ends, it can never return to the past.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;People can often talk passionately for an hour about shared memories, but it is not simple conversation. It is each person&apos;s nostalgia—formerly their own alone—finding someone with whom to share it, and becoming a long-awaited monologue. After each has spoken their own monologue, they suddenly discover that they are standing on opposite sides of a cliff, with nothing left to say.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This seems to explain what happens afterward. It is like two trains moving in the same direction, occasionally running alongside one another. Two people call across the gap, but neither can actually hear the other because the train noise swallows their words—yet they gaze excitedly at each other&apos;s faces while talking.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;For some reason, I kept feeling time pass.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;In the year they spend together like fireworks, the male lead suddenly says this in voiceover, out of nowhere. It carries a sense of impermanence, rooted in death—or in the disappearance of existence. Put simply, he realizes that this time will always come to an end.&lt;/p&gt;
&lt;p&gt;An eighty-minute film is just right; every additional twenty minutes is torture. I finally stopped at &lt;code&gt;1:02:06&lt;/code&gt;, after the male lead says, “After all, if we do not have money, we cannot buy books or watch films, can we? I will work hard.”&lt;/p&gt;
&lt;p&gt;It suddenly hit me with the starkness of reality. Since you put it that way, I suppose I cannot keep watching either.&lt;/p&gt;
&lt;p&gt;From that point on, the film&apos;s filter, atmosphere, and the way the two leads relate to each other will probably turn sharply downward. For now, I will keep only the beautiful image of fireworks blooming, rather than watch them vanish and fall.&lt;/p&gt;
&lt;p&gt;I took quite a few screenshots during this part, because I find the female lead very easy to look at:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/img/covers/202510301059519.jpeg&quot; alt=&quot;&quot; /&gt;
&lt;img src=&quot;../../assets/img/covers/202510301059538.jpeg&quot; alt=&quot;&quot; /&gt;
&lt;img src=&quot;../../assets/img/covers/202510301059397.jpeg&quot; alt=&quot;&quot; /&gt;
&lt;img src=&quot;../../assets/img/covers/202510301059313.jpeg&quot; alt=&quot;&quot; /&gt;
&lt;img src=&quot;../../assets/img/covers/202510301059160.jpeg&quot; alt=&quot;&quot; /&gt;
&lt;img src=&quot;../../assets/img/covers/202510301059199.jpeg&quot; alt=&quot;&quot; /&gt;
&lt;img src=&quot;../../assets/img/covers/202510301100201.jpeg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;If I were younger—say, in high school—I would probably have stayed up to finish the film, then hazily projected myself into it, hazily felt sad, and hazily recommended it to others. Just as I once loved &lt;em&gt;I Want to Eat Your Pancreas&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;But now, I do not envy their relationship at the beginning of the film at all. I probably would not cry over the pancreas any more either.&lt;/p&gt;
&lt;p&gt;Throughout the viewing, a voice in my head kept saying:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Literary romance is such a nuisance. Do not try to make everyone understand you. Do not try to make one person understand all of you. It is such a nuisance.&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;Deep resonance does not require surface compatibility&lt;/h2&gt;
&lt;p&gt;There is another interesting idea that caught my attention: surface compatibility.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;From the beginning, what they had was only “surface-level common interests.” Their ideas and views were actually very far apart. From the start, we can see that they are both lonely, niche people in reality. Everyone longs to be recognized. At first, they are ecstatic to find so many shared interests and can talk about anything, but because they want recognition so badly, they selectively ignore their differences: she does not like watching gas tanks, and he does not really like the mummy exhibition.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;It is very precise, and it made me think about what a person&apos;s real thoughts are and what their surface thoughts are. People with completely different habits and preferences may still resonate deeply and understand each other, while people who love the same works may argue because their views differ. But I do not have that problem for now—I am not dating—so I did not think it through any further.&lt;/p&gt;
</content:encoded></item><item><title>Starting from a NEKOPARA Review</title><link>https://xnnehang.top/en/posts/nekopara-vol-1/</link><guid isPermaLink="true">https://xnnehang.top/en/posts/nekopara-vol-1/</guid><description>Reflections sparked by a Steam review under NEKOPARA: what we want from life, and what we should do.</description><pubDate>Thu, 15 May 2025 00:00:00 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;I was just tied up with something, but I have a free hand now.&amp;lt;br&amp;gt;
Sometimes I often wonder: what, exactly, do you think people live their lives for? Money, love, power, fame—do these things truly matter to us? Perhaps we should spend more time exploring the mysteries of the universe. Earth is somewhat large to humanity, but viewed against the whole universe, it is insignificant. We should vigorously develop technology, go and see the sights beyond the universe, explore whether the universe has an end, and what lies at that end. Could we really be inside a cage, as some people say?&amp;lt;br&amp;gt;
It suddenly occurs to me that the universe may have existed for a very, very long time. Perhaps we are now at the edge of a newborn universe while its center has long gone dark. Or perhaps there is no expanding universe and no multiple universes at all. What we can imagine and infer is only what is “reasonable” within the range of our understanding. Planets are themselves an “unreasonable” existence; only once humanity can create planets will planets become reasonable, and only once humanity can create stars will stars become reasonable.&amp;lt;br&amp;gt;
Some say, “Life is short, so enjoy it while you can.” Some say, “I was born to change—to change humanity, to change the world.” Some say, “In a short hundred years, be true to yourself and die without regret.” Some say, “Do not let your child lose at the starting line.” I think that, right or wrong, these detailed deductions, bold conjectures, and reasonable or unreasonable explanations about the universe are not meant to make “ordinary people” explore it. They are meant to make us think about life and living: how should we treat life, and how should we face “everyone dies; one’s death may weigh heavier than Mount Tai or lighter than a feather”? Perhaps I will be neither light nor heavy—the obscure sort, quickly forgotten, or occasionally mentioned only after someone spits and says, “To be or not to be, that is the question.”&amp;lt;br&amp;gt;
This question is as profound as the origin and future of the universe. I have not reached the point where I can accurately describe my own outlook on life. All I can say is: I hope my life can have regrets, but no lingering remorse. All right, I have something to do. I am off.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;code&gt;https://steamcommunity.com/profiles/76561198366437921/recommended/333600/&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Heh—if I did not tell you, would you think a review like this appeared under NEKOPARA?&lt;/p&gt;
&lt;p&gt;Why not follow its thread and talk about it slowly?&lt;/p&gt;
&lt;p&gt;When I was little, I read a passage that I still remember now. I searched a little for its full text:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The Westminster Abbey epitaph, English version:&amp;lt;br&amp;gt;
When I was young and free and my imagination had no limits, I dreamed of changing the world.&amp;lt;br&amp;gt;
As I grew older and wiser, I discovered the world would not change, so I shortened my sights somewhat and decided to change only my country. But it, too, seemed immovable.&amp;lt;br&amp;gt;
As I grew into my twilight years, in one last desperate attempt, I settled for changing only my family, those closest to me, but alas, they would have none of it.&amp;lt;br&amp;gt;
And now, as I lie on my deathbed, I suddenly realize: If I had only changed myself first, then by example I would have changed my family.&amp;lt;br&amp;gt;
From their inspiration and encouragement, I would then have been able to better my country, and who knows, I may have even changed the world.&amp;lt;br&amp;gt;
&amp;lt;br&amp;gt;
The Westminster Abbey epitaph, Chinese version:&amp;lt;br&amp;gt;
When I was young, I dreamed of changing the world;&amp;lt;br&amp;gt;
When I became more mature, I found that I could not change the world, so I narrowed my sights and decided to change only my country;&amp;lt;br&amp;gt;
When I entered old age, I found that I could not change our country. My final wish was merely to change my family, but that too was impossible.&amp;lt;br&amp;gt;
As I now lie in bed, close to death, I suddenly realize: if I had only changed myself first, then perhaps I could have changed my family;&amp;lt;br&amp;gt;
With my family’s help and encouragement, perhaps I could have done something for my country;&amp;lt;br&amp;gt;
And then, who knows? I might even have changed the world.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;When I first saw it, I only felt that it was quite meaningful. Later, in Fitzgerald, Haruki Murakami, and Camus, I encountered similar ideas: &lt;code&gt;do not judge others, because not everyone has the same conditions as you&lt;/code&gt;, &lt;code&gt;do not try to change others; trying to change them is futile&lt;/code&gt;, and &lt;code&gt;a feeling of stepping outside one’s own situation&lt;/code&gt;. They all happen to echo what was said above.&lt;/p&gt;
&lt;p&gt;But when I look at it now, the sense of warning has faded considerably, and I think of more things instead. Beginning with changing oneself and then gradually reaching the world is, in fact, a &lt;code&gt;butterfly effect&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;In terms of the outcome, it may be possible; in terms of probability, it is almost vanishingly small.&lt;/p&gt;
&lt;p&gt;And this passage seems a little nonsensical. The problem is that &lt;code&gt;if only at the beginning&lt;/code&gt; has the feel of a gambler’s statement: after the dust settles, they feel that if they could start again, they would never gamble. Sugaru Miaki’s novels depict many similar cases. Can someone who has fallen into a pit truly reform? Does a fool become wiser before death? If a bad person sighs over the beauty of the world before dying, are they worthy of God’s forgiveness? My favorites are &lt;em&gt;Three Days of Happiness&lt;/em&gt;, a rescue through and through, and &lt;em&gt;Don’t Cry, Don’t Cry&lt;/em&gt;, an explosion through and through. Both endings are worth accepting, because both have a beautiful girl. I should not say more.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I want to be saved by a beautiful girl too. Would that be too frivolous?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;That was what I felt at the time. For specifics, see [[We Who Have No Tomorrow Fell in Love Yesterday]].&lt;/p&gt;
&lt;p&gt;The reason it is nonsensical is that gamblers have offered similar, moving confessions more than once. Sometimes there is no denying that they truly mean it while confessing. But most gamblers fall into a cycle of zero times or countless times, and very few truly quit. If we had to study why, perhaps not even a paper could summarize it clearly.&lt;/p&gt;
&lt;p&gt;When I was younger, I would have liked this kind of warning. Now, though, I find that it may not be as interesting as &lt;code&gt;Ten years, a dream in Yangzhou; all I earned was a reputation for fickleness in the pleasure quarters.&lt;/code&gt; Ancient poetry often leaves vast blank spaces; it rarely describes an event with concrete objectivity. But if you happen to have a story that can fill that blank space, you may find it quite interesting. I am not claiming to have deep social experience. On the contrary, the story that fills this blank space comes from another game—&lt;em&gt;Fengxin Tower&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;This is the review I wrote in response:&lt;/p&gt;
&lt;p&gt;[[Fengxin Is a Good Name]]&lt;/p&gt;
&lt;p&gt;From here, perhaps I can introduce what I want to say: my answer to the NEKOPARA reviewer’s question of &lt;code&gt;what we want from life, and what we should do&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;For me, the short-term goal is to bring my waifu into reality. It is somewhat like &lt;a href=&quot;https://www.bilibili.com/video/BV14UdqYcEmo/&quot;&gt;【my-neuro】Open-source AI Desktop Companion: a Local Deployment Guide&lt;/a&gt;, though perhaps more complicated, with multiple platforms and so on. But the PC is the platform I spend the most time using and have naturally put the most care into. I am still reinventing the wheel lately. I want to bring the characters I like into “reality.”&lt;/p&gt;
&lt;p&gt;I once wrote something like &lt;code&gt;Following anime is lonely; finishing anime is lonelier still&lt;/code&gt;. Loneliness alone cannot describe that feeling. So I hope the characters’ lives can continue outside their works and keep me company. I have ideas for how to do it, but the engineering effort is a little… Still, anything without a barrier would have been done by someone else long ago.&lt;/p&gt;
&lt;p&gt;From this alone, you may think I am a little unreasonable, just as my high-school homeroom teacher told me that I was a complete idealist and dreamer. In this regard, I truly am impractical: spending what may be the most creative years of my life on something completely unreal and unrealistic.&lt;/p&gt;
&lt;p&gt;But beyond that, I need to add that characters are only containers. What I actually want to keep is a feeling—a feeling I do not want to lose after experiencing it. I hope to preserve it and even convey it to more people. Some record and spread it through novels, some through illustrations, some through music, and so on. I have received quite a few such feelings from web novels too, and it is genuinely wonderful to be able to get that feeling. Anime often expresses the magical color of a work by pouring emotion into it. I want to try writing too, but trying seems like it might be fatal. Perhaps I will keep trying later.&lt;/p&gt;
&lt;p&gt;For me now, how to describe, record, and express this feeling may be what I need to keep doing.&lt;/p&gt;
</content:encoded></item><item><title>After Hua Jiang Hu: Tian Gang — Perhaps True Completion Does Not Exist</title><link>https://xnnehang.top/en/posts/huajianghu-tiangang/</link><guid isPermaLink="true">https://xnnehang.top/en/posts/huajianghu-tiangang/</guid><description>Starting from Hua Jiang Hu: Tian Gang, a reflection on what makes a story feel complete.</description><pubDate>Sat, 15 Mar 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;img src=&quot;../../assets/img/covers/%E7%94%BB%E6%B1%9F%E6%B9%96.jpg&quot; alt=&quot;Hua Jiang Hu: Tian Gang&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;Tian Gang and Qiao&apos;er&lt;/h2&gt;
&lt;p&gt;I have seen people say that this film is nothing more than a collection of formulas, or simply cliché. All I can say is that they have watched too much, and paid too much attention to form.&lt;/p&gt;
&lt;p&gt;Here I only want to discuss one small thing: &lt;strong&gt;what kind of story counts as complete?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The relationship between Yuan Tian Gang and Qiao&apos;er feels more like mutual salvation. Yet as I watched the time the two of them spent together, I unconsciously began to place them side by side in my mind. It felt fitting. Romantic.&lt;/p&gt;
&lt;p&gt;Because I knew Yuan Tian Gang was still alive in the end, I was not saddened by his apparent sacrifice to save His Majesty. But at the ending, I found myself quietly hoping—hoping that Yuan Tian Gang and Qiao&apos;er would celebrate a birthday together.&lt;/p&gt;
&lt;p&gt;Instead, decades flash by in an instant. Only Qiao&apos;er remains, her hair turned silver; Yuan Tian Gang passes through like the wind, leaving behind that hairpin.&lt;/p&gt;
&lt;p&gt;A story and ending like this are exquisitely beautiful. Considered as an essay, they are forceful; considered as a story, they carry a kind of mournful grace.&lt;/p&gt;
&lt;p&gt;But whenever I encounter things like this, I habitually extend them into reality. How can decades simply pass by? What happened between them during that time? Qiao&apos;er only knows that Yuan Tian Gang is dead. How could her state of mind have changed?&lt;/p&gt;
&lt;h2&gt;The Difference Between Immortals and Mortals&lt;/h2&gt;
&lt;p&gt;Yuan Tian Gang has, in this sense, become an immortal. At least in terms of lifespan, he is already no different from what people understand an immortal to be.&lt;/p&gt;
&lt;p&gt;Perhaps immortals differ from people partly because I quietly hope for more stories of Yuan Tian Gang and Qiao&apos;er—perhaps even a lifetime together.&lt;/p&gt;
&lt;p&gt;But a mortal life passes in a flicker to an immortal. Qiao&apos;er will grow old and die, while Yuan Tian Gang will not.&lt;/p&gt;
&lt;p&gt;I also understand Yuan Tian Gang’s original wish not to live, but to die. It overlaps with something I felt when I previously watched &lt;em&gt;A Record of a Mortal’s Journey to Immortality&lt;/em&gt;.&lt;/p&gt;
&lt;h2&gt;What Kind of Story Counts as Complete?&lt;/h2&gt;
&lt;p&gt;Back to the point: what kind of story counts as complete?&lt;/p&gt;
&lt;p&gt;Many stories—novels, anime, games—are defined as having happy endings, normal endings, or bad endings.&lt;/p&gt;
&lt;p&gt;There are also distinctions between a small knife, a medium knife, and a big knife: different degrees of emotional pain.&lt;/p&gt;
&lt;p&gt;Let me analyze it from Yuan Tian Gang’s perspective. Looking back, meeting Qiao&apos;er was a fortunate thing for him, though I cannot guess what he was thinking when he delivered the hairpin at the end.&lt;/p&gt;
&lt;p&gt;From Qiao&apos;er’s perspective, I would at least be despondent for a long time after mistakenly believing Yuan Tian Gang had died. Then, when I saw that hairpin, a thousand feelings would rush through me. Perhaps I would wonder why he never came to see me. Why not show himself, even at the end? (Though the Bad Guy Commander truly appearing would overwhelm anyone, I think Qiao&apos;er could take it.) The scene where she retrieves the note from the fire moved me deeply.&lt;/p&gt;
&lt;p&gt;From Li Chunfeng’s perspective, considering only his final end: he had a kindred spirit beside him, and even after death could still play one last trick on Yuan Tian Gang, leaving him nowhere to look. It feels more like exploring the unknown after death. Having exhausted the patterns of life, he seems to be living toward death—simply departing rather than dying, as if beginning a journey. And once he had mastered physiognomy, Qimen, and every other art, perhaps he had glimpsed some mystery of death in advance. Who can say?&lt;/p&gt;
&lt;h2&gt;The Paradox of Happy Endings&lt;/h2&gt;
&lt;p&gt;From my point of view:&lt;/p&gt;
&lt;p&gt;I have seen very forced happy endings. I still remember how Tian Can Tu Dou spent a very long final chapter writing the ending of &lt;em&gt;Battle Through the Heavens&lt;/em&gt;. It mainly explained the situations of each heroine, another kind of cut-off ending like the one in this film. Yet although it was a happy ending, I suddenly felt sad, because the imaginings opened by the ending were only imaginings—I would never see any more of their stories.&lt;/p&gt;
&lt;p&gt;One of the cut-off endings I encountered early on—perhaps there is a more elegant technical term for it, but I am not a professional—was, I would say, perfected in &lt;em&gt;Norwegian Wood&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Of course, I have seen bad endings too.&lt;/p&gt;
&lt;p&gt;If a character dies, there is no continuation. Erii was unquestionably written to death by Jiang Nan in the third volume of &lt;em&gt;Dragon Raja&lt;/em&gt;, and for a long time I remained caught in the wish that she could return to life.&lt;/p&gt;
&lt;p&gt;Ah, human desire is limitless. In pursuit of completion, we want this and that, only to discover that true completion does not exist at all. It seems that only the story itself remains profound.&lt;/p&gt;
</content:encoded></item><item><title>On Mortal Lives in Renegade Immortal and A Record of a Mortal&apos;s Journey to Immortality</title><link>https://xnnehang.top/en/posts/xianni-huafan/</link><guid isPermaLink="true">https://xnnehang.top/en/posts/xianni-huafan/</guid><description>The mortal-life realizations in Renegade Immortal and the secluded life in A Record of a Mortal&apos;s Journey to Immortality: two kinds of mortal hearts on the path to immortality.</description><pubDate>Tue, 18 Feb 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I do not know why I am always so drawn to stories and scenes like these.&lt;/p&gt;
&lt;p&gt;Maybe it is because I can never quite understand them, yet instinctively want an answer. In &lt;em&gt;A Record of a Mortal&apos;s Journey to Immortality&lt;/em&gt;, I cannot understand what Han Li&apos;s Dao heart is, why missing someone can mean missing them for a lifetime, or what kind of regret separates immortals from mortals. What does it feel like when neither the people who know you nor the people you know remain in this world?&lt;/p&gt;
&lt;p&gt;In &lt;em&gt;Renegade Immortal&lt;/em&gt;, I cannot understand what Wang Lin felt when, before reaching the Spirit Transformation stage, he lived out a whole life as a mortal carpenter; or what it felt like to finally touch the Great Dao that belonged to him.&lt;/p&gt;
&lt;h2&gt;Emotional scenes and dramatic writing&lt;/h2&gt;
&lt;p&gt;If the part I love most in &lt;em&gt;A Record of a Mortal&apos;s Journey to Immortality&lt;/em&gt; is the emotional writing between Han Li and Mo Caihuan in “Farewell to Tiannan,”&lt;/p&gt;
&lt;p&gt;then it is these lines:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“Big Brother Han, you are always like this. When you meet a question that is hard to answer, you just say nothing.”&lt;/p&gt;
&lt;p&gt;“Without a spiritual root, can I really not become an immortal cultivator?”&lt;/p&gt;
&lt;p&gt;“Big Brother Han, we will meet again, right?”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;P.S. I did not expect someone else to feel exactly as I do. They edited together every one of these scenes, neither more nor less. There is less buildup and only the dialogue, though, so it does not hit as hard as the full version.
&lt;a href=&quot;https://www.bilibili.com/video/BV1jv411Y7WD/&quot;&gt;“Big Brother Han, you are always like this. When you meet a question that is hard to answer, you just say nothing.” Why does the production team have to do this? Are they trying to make me cry?&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;But thinking about it now, it is even more about the acting through the eyes. The &lt;em&gt;Mortal&apos;s Journey&lt;/em&gt; animation differs from Tencent&apos;s many other animations—such as &lt;em&gt;Throne of Seal&lt;/em&gt;, &lt;em&gt;Soul Land&lt;/em&gt;, &lt;em&gt;Battle Through the Heavens&lt;/em&gt;, and &lt;em&gt;Swallowed Star&lt;/em&gt;. Whatever their budgets, those series do not put much effort into the eyes. &lt;em&gt;Sword Coming&lt;/em&gt; may be an exception. But the eyes in &lt;em&gt;Mortal&apos;s Journey&lt;/em&gt; feel very different to me. Every blink, or the exact point at which a character focuses their gaze, often conveys an emotion. What I feel most strongly is a kind of quiet grievance. One glance lasts a lifetime.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/img/xianni-huafan/caihuan.png&quot; alt=&quot;Caihuan&quot; /&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Why does Caihuan seem less pretty now?!&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;In most animated series, characters do not focus their eyes on the camera; they focus on other characters in the frame, usually turned sideways and striking a pose. Perhaps &lt;em&gt;Mortal&apos;s Journey&lt;/em&gt; captures faces more directly, so it feels as if the characters&apos; gaze is focused on the viewer. I think that feeling is rare, and it is one reason I like it. (Not every shot or character works that way—male characters almost never do—but I find the expressiveness in the female characters&apos; eyes hard to resist.)&lt;/p&gt;
&lt;p&gt;And there is Chen Qiaoqian, the Forget-Worry Fairy. Across several meetings and partings, the relationship grows closer through all the secret doses of Forget-Worry pills.&lt;/p&gt;
&lt;p&gt;And why can Han Li not stop for anyone, not even for a moment? After all, a mortal lifetime is only an instant to an immortal cultivator. What is a Dao heart? Why pursue the Dao?&lt;/p&gt;
&lt;p&gt;Wang Lin&apos;s understanding of the Dao heart in &lt;em&gt;Renegade Immortal&lt;/em&gt; differs from Han Li&apos;s. Wang Lin is more often unable to choose his own path: first for his parents, later for revenge, then to revive the woman he loves. Things keep dragging him forward, and there is nothing wrong with that. But I want to know what keeps Han Li moving onward.&lt;/p&gt;
&lt;p&gt;The emotional writing for Wang Lin and Li Muwan is also a little thin; it did not shake me the way the ending of “Farewell to Tiannan” in &lt;em&gt;Mortal&apos;s Journey&lt;/em&gt; did. Perhaps I am simply getting older.&lt;/p&gt;
&lt;p&gt;Yet while watching &lt;em&gt;Renegade Immortal&lt;/em&gt;, I really wanted another stretch added to their relationship: when Wang Lin had just reached the Yuntian Sect to recover his cultivation and form his Nascent Soul. Was he not only at the beginning of the Qi Refinement stage then? In the animation, he learns that Li will be forced to become someone else&apos;s dual-cultivation partner in three months. Forced into action, he reveals his identity and forms his Nascent Soul in those three months. Their relationship does not deepen further; it only revisits old dreams. But each time Han Li meets Senior Sister Chen or Mo Caihuan, the relationship actually advances, eventually becoming the kind of regret where a blue dress ruins a lifetime.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/img/xianni-huafan/limuwan.png&quot; alt=&quot;Li Muwan&quot; /&gt;&lt;/p&gt;
&lt;p&gt;If I were adapting or writing it, I would lengthen that period. A Core Formation cultivator has no shortage of time; one or two years are no more than a retreat. Wang Lin&apos;s master was in retreat then, so Wang Lin had no choice but to ask Patriarch Li for guidance. That would make sense. During that time, more could happen; more scenes could show Li Muwan quietly grieving from longing, and sensing that Wang Lin feels familiar. A little more buildup, a little more feeling, and then the reveal: that is the drama I wanted.&lt;/p&gt;
&lt;p&gt;Wang Lin and Patriarch Li do not have enough emotional scenes. It is a sore point. Just think: what good material. Yang Guo and Little Dragon Girl had so much to work with, and these two are separated by a generation of kinship.&lt;/p&gt;
&lt;p&gt;What a pity—one nearly recognized the other, while the other refused to take the initiative. Wang Lin would not even ask for help with alchemy.&lt;/p&gt;
&lt;h2&gt;Living as a mortal&lt;/h2&gt;
&lt;p&gt;But each story has its strengths.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;A Record of a Mortal&apos;s Journey to Immortality&lt;/em&gt; does better at emotional dramatic writing and irretrievable regret; &lt;em&gt;Renegade Immortal&lt;/em&gt; does better at the realization gained by living as a mortal.&lt;/p&gt;
&lt;p&gt;I remember that before Han Li went into retreat to form his Core, he once lived as an ordinary person, refining artifacts and drawing talismans for an entire lifetime. I have not had time to revisit it, so I may be missing or misremembering details.&lt;/p&gt;
&lt;p&gt;In &lt;em&gt;Renegade Immortal&lt;/em&gt;, before reaching the Spirit Transformation stage, Wang Lin becomes an ordinary young carpenter. He carves demon beasts, great cultivators, family, and friends, and lives out a whole life.&lt;/p&gt;
&lt;p&gt;Both of them choose to hide in the marketplace. I am not sure whether I am using that phrase correctly.&lt;/p&gt;
&lt;p&gt;From the people they meet, I remember Han Li encountering a Go player. The Go player&apos;s story goes like this:&lt;/p&gt;
&lt;p&gt;The Go player was exceptionally gifted from a young age; no peer or acquaintance could match his skill.&lt;/p&gt;
&lt;p&gt;Then one day, an immortal passed by and found him. They made a wager: if the Go player could win one game against the immortal within three days, the immortal would teach him immortal arts and lead him into the immortal sect.&lt;/p&gt;
&lt;p&gt;I have forgotten how that story ends. By the time the Go player faced Han Li, his hair was already white. I do not remember whether he had cultivation, but one line—“life is like Go; once a move is played, there is no regret”—left a deep impression on me. It also reflects Han Li&apos;s choice. He chooses to pursue the Dao wholeheartedly, but can he truly have no regrets? Even if he has no family left and every beauty becomes dry bones? Even if no one ultimately reaches the so-called Great Dao of eternal life, can he still not regret the choice he made?&lt;/p&gt;
&lt;p&gt;The Go player&apos;s final answer was: winning and losing do not matter; once a move is played, there is no regret. He said it with great certainty, and it gave me the feeling that Han Li has the same attitude.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/img/xianni-huafan/qizi.png&quot; alt=&quot;Go piece&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Mortal&apos;s Journey&lt;/em&gt; expresses its mortal-life realization through the Go player&apos;s experience. It is brief, powerful, and certain. Spring comes and autumn goes, but the answer does not change. It is only a sorting out and adjustment of the heart.&lt;/p&gt;
&lt;p&gt;Wang Lin in &lt;em&gt;Renegade Immortal&lt;/em&gt;, on the other hand, has far more mortal feeling than Han Li. If he could return to Wang Village and live with his parents, even if it meant giving up the Great Dao of eternal life, I do not think he would hesitate in the slightest. He feels deeply, honors loyalty and righteousness, and gives himself wholly to feeling—that is probably Wang Lin. He never seeks immortality or the immortal path for its own sake. He only wants to protect his people and his family. That is his Dao heart.&lt;/p&gt;
&lt;p&gt;So the mortal-life writing in &lt;em&gt;Renegade Immortal&lt;/em&gt; feels more like real everyday life. Across from him is the blacksmith&apos;s family; he watches a child grow up and eventually become a father, and watches the original blacksmith slowly grow old and finally lie in a coffin.&lt;/p&gt;
&lt;p&gt;Wang Lin&apos;s Dao lies in a pot of homemade fruit wine every day (or perhaps some other wine?), in the Mid-Autumn Festival, Lantern Festival, Lunar New Year&apos;s Eve, and Dragon Boat Festival that return each year. It lies in the care of others, and in finding the warmth of home in the blacksmith&apos;s family.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/img/xianni-huafan/wanglin-huafan.png&quot; alt=&quot;Wang Lin living as a mortal&quot; /&gt;&lt;/p&gt;
&lt;p&gt;But it also lies in everything passing away. So his Great Dao is both the extreme of life and the extreme of death: life and death transform into one another, while he remains. That is his Dao.&lt;/p&gt;
&lt;p&gt;Overall, I prefer &lt;em&gt;Renegade Immortal&lt;/em&gt;&apos;s portrayal of living as a mortal, because that is my own temperament too. If I were ever to find a Great Dao of my own, it would probably come this way.&lt;/p&gt;
&lt;p&gt;But compared with Wang Lin, I cannot even live as long as a Nascent Soul cultivator in the first place.&lt;/p&gt;
</content:encoded></item><item><title>The Long Ballad: Even After a Thousand-Li Farewell, We Must Part at Last</title><link>https://xnnehang.top/en/posts/changge-xing/</link><guid isPermaLink="true">https://xnnehang.top/en/posts/changge-xing/</guid><description>Reflections on the manga and television adaptation of The Long Ballad</description><pubDate>Sun, 16 Feb 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;A Brief Preface&lt;/h2&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/img/changge-xing/snow-scene.jpeg&quot; alt=&quot;Surrender in the snow&quot; /&gt;&lt;/p&gt;
&lt;p&gt;This was the scene that moved me most deeply in the manga. The snow had not just begun to fall; it was a bitter, freezing storm that, if it continued, would be enough to force an army to retreat. Li Changge was badly wounded, suffering from a chill and burning with fever. Yet dressed only in thin, plain clothes, she walked barefoot through the snow, carrying Governor Gongsun&apos;s severed head all the way to the Eagle Division&apos;s Tegin to offer her surrender. After being captured, she continued to suffer from illness and her wounds. At that point in the manga, that fool Sun did not even know Li was a woman. To him, Li Changge was merely a defeated opponent who had once caused him trouble. He admired her a little, but not much; there was certainly none of the comfortable care and protection he constantly gave her in the drama.&lt;/p&gt;
&lt;p&gt;I no longer remember clearly whether Sun&apos;s Eagle Division was a righteous army, but Sun himself was certainly no saint.&lt;/p&gt;
&lt;p&gt;I went back to watch the scene again just now. The production team did at least reproduce the dialogue faithfully, so I will give them that.&lt;/p&gt;
&lt;p&gt;The drama differs from the manga in many places. Some changes I dislike, while others I accept. I approve of changing Sun&apos;s characterization and making him hopelessly devoted to Changge; this gives them the best possible ending. (I think they may eventually end up on opposing sides in the manga, although it is a little unfortunate that the drama reveals Li is a woman so early. I would rather have watched Sun first take Li for a man and only discover the truth later.) I agree with making Li Shimin&apos;s attitude explicit and showing that he supports Changge. I also approve of adding Princess Yong&apos;an&apos;s storyline and letting the two narratives progress in parallel. But I cannot accept turning Mimi into someone so weak, indecisive, and unlikeable. If I had to summarize it, I could only say this: I saw what I wanted to see, despite seeing many things along the way that I did not want at all. After finishing it, I still love the drama and have placed it on my rewatch list—a television series set high upon a shelf, kept only for remembrance.&lt;/p&gt;
&lt;h2&gt;A Little Aside: The Princess Is Fair as Jade, the Princess Is Peerless&lt;/h2&gt;
&lt;p&gt;Before watching, I wrote that although Li Changge has Western Region ancestry, she unmistakably has the black-haired appearance of the Central Plains. I thought Gulnazar would have been better suited to the role, including in the shape of her face. I also wrote that Dilraba looked a little too guileless.&lt;/p&gt;
&lt;p&gt;I wrote something similar about Ashile Sun: he is of Turkic descent, and people of the grasslands ate plenty of beef and mutton, so Wu Lei&apos;s frame seemed too slight for the role. They should at least have cast someone with the build of a slightly heavier Huang Xiaoming.&lt;/p&gt;
&lt;p&gt;Later, once the two of them drew me into the story, I had no complaints at all. None of Li Changge&apos;s cunning or quick wit was lost. I especially enjoyed how, while disguised as a man, she acted like a player and collected one “little sister” after another.&lt;/p&gt;
&lt;p&gt;The princess is fair as jade; the princess is peerless under heaven. Hahaha!&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/img/changge-xing/changge-beauty.jpeg&quot; alt=&quot;The princess&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;The Long Ballad: Even After a Thousand-Li Farewell, We Must Part at Last&lt;/h2&gt;
&lt;p&gt;This is a drama I will probably never watch all the way through again in my lifetime, yet it is also a drama with enough in it to last me a lifetime.&lt;/p&gt;
&lt;p&gt;That sounds contradictory. I probably will not rewatch it because many of its adaptations made me deeply uncomfortable. Mimi Guli was rewritten as weak and devoid of agency. Wei Shuyu and Hao Du&apos;s misunderstanding of Changge persisted almost until the end, with one obstacle after another placed in her way. So much screen time should not have been spent on conflict between Minister Du and Changge. It even crowded out the storyline that should have belonged to Mobei. I had eagerly awaited that development: as the niece by blood of both the King of Mobei and Li Shimin, what could Changge have done for the relationship between Mobei and the Great Tang? What role might her journey to Yanmen have played in such a chaotic age? That was the story I wanted. I wanted Changge to go there in her own right as the King of Mobei&apos;s niece, not to be hastily granted a title and sent there as someone&apos;s younger sister.&lt;/p&gt;
&lt;p&gt;Many of the adaptations felt inappropriate to me, though in retrospect perhaps the story I imagined was simply too grand in scale. That may also explain why, at the end of the drama, I still felt a lingering discomfort with Changge and Sun&apos;s decision to withdraw into the wilderness.&lt;/p&gt;
&lt;p&gt;The lesser recluse hides in the wilds; the greater recluse hides in the marketplace.&lt;/p&gt;
&lt;p&gt;I do not fully understand what this saying means in concrete terms. But I think Changge and Sun chose the former.&lt;/p&gt;
&lt;p&gt;I cannot imagine what would ultimately become of the two of them, but I know the drama&apos;s ending was the best original ending it could have given them. In the manga, whether Changge and Sun will eventually turn against one another remains unknown. In the drama, at least, Sun never doubted or hurt Changge. It may be the behavior of a man hopelessly in love, but it was what I wanted to see. In the manga, Sun never shows the same clear devotion to benevolence and justice that Changge does, nor does it suggest that they share the same aspirations. He merely tells her that if they find themselves on opposing sides one day, they should cross blades without mercy.&lt;/p&gt;
&lt;p&gt;I seem to remember them sharing a drink. Was that the last chapter before the hiatus?&lt;/p&gt;
&lt;p&gt;Whether it was the relationship between Changge and Sun, the relationship between Changge and her second uncle Li Shimin, Minister Du&apos;s relationship with her at the end, or ultimately everyone&apos;s view of Li Changge, I agreed with and loved how it all concluded.&lt;/p&gt;
&lt;p&gt;Chang&apos;an may be a place she can never return to, but it is still there.&lt;/p&gt;
&lt;p&gt;Empress Xiao was the same. Even after the Sui had fallen, when she returned to Chang&apos;an, she said that she had come home.&lt;/p&gt;
&lt;p&gt;Besides, wherever Li Shimin—Li Changge&apos;s second uncle—is, that place will always be Li Changge&apos;s home.&lt;/p&gt;
&lt;p&gt;It is just that after two days of watching from morning to night, plus another entire morning, my liver was beginning to feel faint.&lt;/p&gt;
&lt;p&gt;I have seen you off a thousand li; here, at last, we must part.&lt;/p&gt;
&lt;p&gt;At the end, when Li Shimin learned that Li Changge had faked her death and still did not wish to return to Chang&apos;an, he smiled in acceptance. He supported her choice. Faced with this version of Li Changge, could I still cling to my original, naive wish? I only missed the sight of Li Changge in red robes, galloping through Chang&apos;an like its little tyrant. I only missed the Chang&apos;an I had imagined, the Great Tang that had never existed. Only at the end did I realize that, like Princess Yicheng, I was merely a mad dreamer chasing a fantasy.&lt;/p&gt;
&lt;p&gt;Li Changge, thank you for keeping me company all this way. Perhaps I am even more hesitant and long-winded than Young Master Wei. Have I found my path again?&lt;/p&gt;
</content:encoded></item><item><title>A Snow Rabbit Twenty Centimeters from Spring and The Shawshank Redemption</title><link>https://xnnehang.top/en/posts/snow-rabbit-shawshank/</link><guid isPermaLink="true">https://xnnehang.top/en/posts/snow-rabbit-shawshank/</guid><description>A rabbit and a prisoner: two tunnels, two kinds of freedom.</description><pubDate>Sun, 16 Feb 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;img src=&quot;../../assets/img/covers/snow-rabbit-shawshank.jpg&quot; alt=&quot;A snow rabbit in spring&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;Digging&lt;/h2&gt;
&lt;p&gt;First of all, this is a story about digging tunnels.&lt;/p&gt;
&lt;p&gt;A prisoner in Shawshank Prison and a rabbit in winter were both digging for freedom.&lt;/p&gt;
&lt;p&gt;The result was that the prisoner spent twenty-seven years digging toward the sewer, waited for his chance, and escaped successfully.&lt;/p&gt;
&lt;p&gt;The rabbit returned to the surface after more than a month. With no water or food, it mistook cardboard for food and snow for water. Its owner found it only after the snow melted. It was finally saved, and then optimistically pestered its owner for food again.&lt;/p&gt;
&lt;h2&gt;Freedom&lt;/h2&gt;
&lt;p&gt;The idea that the rabbit was digging for freedom is something I invented. It is like saying birds do not want to be enclosed in cages, or fish do not want to stay in fish tanks. Those ideas are things people invent too.&lt;/p&gt;
&lt;p&gt;Do fish really not want to be confined in tanks? If so, are there individual differences, just as some people prefer solitude while others prefer socializing? Perhaps fish do too: some may prefer quietly sleeping in a tank instead of worrying in the sea.&lt;/p&gt;
&lt;p&gt;I cannot explain whether the rabbit truly longed for freedom or even understood what freedom was.&lt;/p&gt;
&lt;p&gt;But that prisoner really did dig for freedom. The freedom here, however, is something subtler.&lt;/p&gt;
&lt;p&gt;Let us call the prisoner K.&lt;/p&gt;
&lt;p&gt;A scene in both the novel and the film has K help the captain of the guards arrange a $35,000 gift to his wife without tax being withheld. In exchange, K asks that each of his coworkers receive three bottles of beer.&lt;/p&gt;
&lt;p&gt;K lets his coworkers taste &lt;code&gt;freedom&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;After hard work, they can drink cold beer while watching the sunset. At that moment, they feel as if they are not in prison.&lt;/p&gt;
&lt;p&gt;This freedom has limits, but it leads toward freedom in the broader sense.&lt;/p&gt;
&lt;p&gt;The freedom people in prison can feel is not necessarily freedom from the cage. D, the library keeper, has been institutionalized for fifty years and comes to depend completely on prison life. In prison, he is one of the few educated people, a librarian with a place of his own. Outside it, he is only a sixty-eight-year-old man with arthritis.&lt;/p&gt;
&lt;p&gt;So &lt;code&gt;making someone feel no longer in prison&lt;/code&gt; is a kind of freedom, or at least temporary freedom.&lt;/p&gt;
&lt;p&gt;That &lt;code&gt;not being in prison&lt;/code&gt; is very different from literally being outside prison. It is an imagined freedom and purity, like the imagined Tang dynasty and Chang&apos;an in &lt;em&gt;The Long Ballad&lt;/em&gt;: it exists, yet it is false, and also incomparably pure. At the very least, it offers spiritual satisfaction.&lt;/p&gt;
&lt;h2&gt;Hope&lt;/h2&gt;
&lt;p&gt;The second moment was created for the film. K uses the prison broadcast system to play an Italian song with a woman&apos;s voice. When the prisoners hear it, they all feel that something is there—or that something does not belong here at all.&lt;/p&gt;
&lt;p&gt;Perhaps that is hope.&lt;/p&gt;
&lt;p&gt;Most prisoners serving life sentences had discarded it long ago. Yet in that moment, the music returns a little of it to them, even if they do not seem to recognize what the feeling is.&lt;/p&gt;
&lt;p&gt;K says that the music will keep bringing him that feeling for a long time. Because music creates memory, he can recall the song and feel it again whenever he wants.&lt;/p&gt;
&lt;p&gt;I understand it a little, but it is hard to truly experience.&lt;/p&gt;
&lt;h2&gt;Passing the time&lt;/h2&gt;
&lt;p&gt;Prison is a huge pressure vessel.&lt;/p&gt;
&lt;p&gt;So the guards and prison leadership turn a blind eye and let prisoners have hobbies, so long as those hobbies are safe.&lt;/p&gt;
&lt;p&gt;It is said that one man carved three statues: a baby boy, a bearded young man, and a middle-aged man. He said they represented the three stages of God.&lt;/p&gt;
&lt;p&gt;Those three statues were apparently later displayed in the governor&apos;s exhibition room.&lt;/p&gt;
&lt;p&gt;Some people also earn college diplomas there.&lt;/p&gt;
&lt;p&gt;But the people there seem to share certain traits. Every prisoner can read novels about courts and prison breaks over and over without getting tired of them, even more than pornographic novels.&lt;/p&gt;
&lt;p&gt;Perhaps those stories contain their desire for freedom and their remaining hope, though, as usual, it is difficult to notice.&lt;/p&gt;
&lt;h2&gt;Pressure&lt;/h2&gt;
&lt;p&gt;For K, who decides to escape, the pressure is unmatched.&lt;/p&gt;
&lt;p&gt;One day, he discovers that the concrete in the wall seems rather loose, so he begins to dig.&lt;/p&gt;
&lt;p&gt;The pressures of digging include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;He may have a cellmate, who could expose his secret.&lt;/li&gt;
&lt;li&gt;He may be transferred to another prison midway through, and being found digging there would bring a harsher punishment.&lt;/li&gt;
&lt;li&gt;Without prison blueprints, it is hard to know where he will dig to. There is an interesting story about a prisoner who dug into a police office, poked out his head, and was immediately caught again. I do not know whether it is true.&lt;/li&gt;
&lt;li&gt;If he is granted parole midway through and the tunnel is discovered when his cell is cleared out, he will end up back in prison.&lt;/li&gt;
&lt;li&gt;He cannot know how long he will need to keep digging: ten years, twenty years, or fifty. In reality, it takes him twenty-seven.&lt;/li&gt;
&lt;li&gt;Being caught after successfully digging the tunnel would be even worse. Many people escape prison; very few succeed.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If I faced these pressures, I would collapse. I would be unable to think normally, wear a strange expression, and worry all day.&lt;/p&gt;
&lt;p&gt;That is why K&apos;s self-control is what stays with me most from the whole book.&lt;/p&gt;
&lt;p&gt;One comment says that K reveals what benefits him only a little at a time, while saying nothing at all about what would hurt him. He drinks only four times a year: twice on his birthday, then at Christmas and Lunar New Year&apos;s Eve.&lt;/p&gt;
&lt;p&gt;I have very little self-control, and perhaps that is why it matters so much to me.&lt;/p&gt;
&lt;h2&gt;Escape&lt;/h2&gt;
&lt;p&gt;This also seems to be the title of a short-story collection.&lt;/p&gt;
&lt;p&gt;I seem especially drawn to this kind of subject. Is it because I too feel trapped in a cage?&lt;/p&gt;
&lt;p&gt;How can my hope and freedom draw nearer?&lt;/p&gt;
</content:encoded></item><item><title>You Are My Glory</title><link>https://xnnehang.top/en/posts/you-are-my-glory/</link><guid isPermaLink="true">https://xnnehang.top/en/posts/you-are-my-glory/</guid><description>A letter about You Are My Glory.</description><pubDate>Wed, 15 Jan 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;img src=&quot;../../assets/img/covers/you-are-my-glory.jpg&quot; alt=&quot;You Are My Glory&quot; /&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;It turns out you only ever passed by my side,
while I mistook you for a rainbow falling from the sky.~&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The first television drama I ever watched, ya.&lt;/p&gt;
&lt;p&gt;And Yang gave me another one. Thank you—and it stars a pair I used to ship so much that I even dreamed of them becoming a couple. No regrets now. Besides, I think I could watch this one for a lifetime.&lt;/p&gt;
&lt;p&gt;A slightly untimely review of a television drama today.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;To Qiao Jingjing:&lt;/p&gt;
&lt;p&gt;I hope this letter finds you well.
I finished the almost twenty years of your story with Teacher Yu in three days. The scene I remember most clearly is when you used a broken air purifier as an excuse to get Teacher Yu to your home, then turned back in the backlight wearing your carefully calculated makeup. I really want to see that look again, but I am afraid I would fall in and never come back out, just like Teacher Yu.&lt;/p&gt;
&lt;p&gt;When you visited the launch site as a family member, one of the staff said that he had grown up watching your television dramas. At that moment, I suddenly thought without meaning to: from the first time I met you and Teacher Yu until now, I seem to have grown up too. Teacher Yu seems patient with age, but I feel restless about it instead.&lt;/p&gt;
&lt;p&gt;Also, I found that I used to prefer watching the two of you shower each other with sweetness. Now, though, I find a different emotion in the two episodes where you are wronged. Sadness seems to move me more deeply than happiness. But it is not my sadness; it is someone else&apos;s sadness, perhaps Teacher Yu&apos;s. As an observer, maybe this is why so many people end up preferring tragedy to comedy. I used to be completely unable to accept anything too painful.&lt;/p&gt;
&lt;p&gt;Of course, I still feel that way. I do not want a work to make its ending deliberately heartbreaking merely to force a deep impression on me. I am also happy for you and hope you will keep walking together to the end. Although I nearly laughed when the first confidant, Guan Zai, ranked ahead of you—Teacher Yu called him first to share the good news, and only then called you.&lt;/p&gt;
&lt;p&gt;But it is fine. It is fine.&lt;/p&gt;
&lt;p&gt;Besides the two main reasons for this drama—you and Teacher Yu, both of whom I have watched since I was young—there is another: &lt;em&gt;The Long Ballad&lt;/em&gt;. In that play within a play in the desert, you played Li Changge, right? The third thing I love most is &lt;em&gt;The Long Ballad&lt;/em&gt;. I do not understand why that comic attracts me so much, but it has always been first in my heart. It is subtle. The attraction is not only about its plot or character settings; it is comprehensive, just as this drama attracts me.&lt;/p&gt;
&lt;p&gt;Why did I suddenly start watching television dramas? I have a roommate who watches them between programming sessions, whatever is most popular that season. But since around college, I have had a prejudice that television dramas are simply a waste of time. I do not know where that prejudice came from, but I have held it for a long time.&lt;/p&gt;
&lt;p&gt;But during the holiday, a poster of you and Teacher Yu flickered across the corner of my eye while I was eating, and I clicked in without thinking. Thank you for keeping me company for three days.&lt;/p&gt;
&lt;p&gt;Thank you for the nostalgic feeling your performance gave me. And thank you for making me realize that I am actually in a pretty bad place right now.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I have been lying low for too long. Without realizing it.&lt;/p&gt;
</content:encoded></item><item><title>Imouto Life</title><link>https://xnnehang.top/en/posts/imouto-jinsei/</link><guid isPermaLink="true">https://xnnehang.top/en/posts/imouto-jinsei/</guid><description>On fading feelings, new encounters, and the work required to sustain an emotion.</description><pubDate>Fri, 18 Oct 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;img src=&quot;../../assets/img/covers/imouto-jinsei.png&quot; alt=&quot;Imouto Life&quot; /&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Whenever a new book comes out, Little Sister visits each nearby bookstore to see how her own books are selling. But after a few more years, once she has grown used to it, perhaps she will stop going to bookstores.&lt;/p&gt;
&lt;p&gt;Human beings are creatures who easily grow accustomed to things. Whether sorrow or joy, we can gradually adapt to both.&lt;/p&gt;
&lt;p&gt;[No, that is not right…]&lt;/p&gt;
&lt;p&gt;Rather than adapting to those feelings, perhaps it would be more accurate to say that the feelings themselves have faded.&lt;/p&gt;
&lt;p&gt;Joy grows thin with time. Once you realize that, loneliness inevitably rises in your heart. But if you keep walking a few more steps, even that loneliness will fade. Maintaining the intensity of a feeling is difficult. If you want to preserve it, you must offer a considerable price. No matter how noble that feeling may be, this is always true.&lt;/p&gt;
&lt;p&gt;[And because it cannot be renewed, memories begin to fade. There are limits to what the mind can remember. Even if you do not want to forget, memories still grow hazier and hazier. If you do not want that to happen, then of course you would not want to leave.]&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;It matches exactly what I felt after watching the &lt;em&gt;Soul Land&lt;/em&gt; anime some time ago. I watched obsessively, neglecting food and sleep, for a short five-day stretch. The feelings afterward were incredibly sincere and intense. I did not want to let them go, but I also knew they would fade and be forgotten. So I wrote something like, “What I am afraid of is forgetting.” But thinking about it now, I can barely even remember what it felt like to be afraid of forgetting.&lt;/p&gt;
&lt;p&gt;Feelings must be affirmed and sustained through contact.&lt;/p&gt;
&lt;h2&gt;It Is Not Time That Dilutes Feelings, but New Encounters&lt;/h2&gt;
&lt;p&gt;I had not considered this before. I thought that as time passed, I would inevitably forget little by little.&lt;/p&gt;
&lt;p&gt;In fact, it is not time that dilutes emotions, but the new encounters hidden within time. After &lt;em&gt;Battle Through the Heavens&lt;/em&gt;, I encountered many more things: &lt;em&gt;Fighter of the Destiny&lt;/em&gt;, &lt;em&gt;Yuan Zun&lt;/em&gt;, &lt;em&gt;The Great Ruler&lt;/em&gt;, and so on. It was not time that made me forget, but new encounters—and not only with novels.&lt;/p&gt;
&lt;p&gt;I find it remarkable that, after three years of high school, Little Sister still retains that longing for her “brother” and lives almost entirely with the aim of attending his university. She has not forgotten that longing with time. Instead, she is like a mayfly living on a single drop of blood from years ago. She remembers drawing diaries and all the outings they took together during summer vacations. She has no new encounters, living only on memories.&lt;/p&gt;
&lt;p&gt;It is precisely these almost impossible conditions that let Little Sister appear at her brother’s door after three years of high school, almost unchanged.&lt;/p&gt;
&lt;h2&gt;Am I Part of the World?&lt;/h2&gt;
&lt;p&gt;In the eyes of the world, a sibling complex seems to be something unforgivable and intolerable; naturally, it is first of all unacceptable.&lt;/p&gt;
&lt;p&gt;But after reading this work, after personally “experiencing” the feelings between siblings—especially as the novel depicts them—I can no longer call it inappropriate.&lt;/p&gt;
&lt;p&gt;In the novel, the almost Platonic love between the brother and sister is truly enviable to me. And it is beyond reproach.&lt;/p&gt;
</content:encoded></item><item><title>What I Talk About When I Talk About Running: Reading Notes</title><link>https://xnnehang.top/en/posts/talking-about-running/</link><guid isPermaLink="true">https://xnnehang.top/en/posts/talking-about-running/</guid><description>On running, focus, freedom, and resistance.</description><pubDate>Tue, 15 Oct 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;img src=&quot;../../assets/img/covers/talking-about-running.jpg&quot; alt=&quot;What I Talk About When I Talk About Running&quot; /&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I am not here to make grand pronouncements or rally everyone with, “Come on! Let’s run every day and stay healthy forever!” In the end, these are only fragments of thought, or perhaps questions and answers I pose to myself—what, for me personally, does keeping on running really mean? Nothing more.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;When writing this book, the author did not yet know what running meant to him either. He was simply exploring it.&lt;/p&gt;
&lt;p&gt;Most of the novels and films I watch are probably like that: they do not put a clear position on display, and perhaps the author did not have a definite answer while creating them either. They were simply exploring.&lt;/p&gt;
&lt;p&gt;“An essay is born whole by nature; a deft hand happens upon it by chance.” That perhaps captures this kind of exploration. The more one tries to force an analysis of the author’s “ideas” or an article’s “central theme,” the more foolish it feels.&lt;/p&gt;
&lt;p&gt;That is why I used to dislike reading-comprehension questions so much. A good novel begins with so many possibilities, yet a standard answer fixes it within the interpreter’s own limitations.&lt;/p&gt;
&lt;p&gt;But I realized that I had recently been trying to do something similar myself. Frightening. At most, I can discuss some problems in my own existence, not analyze the author’s “ideas.” About myself, not the work: that is what I want to do. I could add this to my review criteria.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The wish to be alone has remained unchanged in my heart. So running for an hour every day, to secure a period of silence that belongs only to me, has become an important practice for my mental health. At least while running, I do not need to talk to anyone or listen to anyone. I only need to look at the scenery around me and gaze inward. Nothing can replace that.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;The thoughts that come to mind while running are much like clouds in the sky: different shapes, different sizes. They drift in, and they drift away.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;When I run, I always look up at the sky every so often. I used to run around three-thirty in the afternoon, when it was very hot (no sunscreen, no hat—I was brave). The sky changes fastest then: direct sunlight turns into sunset glow, then dusk, then darkness. All of that happens within two hours.&lt;/p&gt;
&lt;p&gt;While running, all the “serious” and “important” things seem not to surface in my mind. At first, I only need to care about my stamina, then my breathing. After about half an hour, I may enter a kind of meditative state. I have not experienced that in a long time.&lt;/p&gt;
&lt;p&gt;Running feels a lot like meditation, because I often run half asleep, and I am half asleep when I meditate too.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I have thoroughly arrived at my fifties. When I was young, this was unimaginable.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;For Murakami, the twenty-first century was unimaginable when he was young. For me, I probably will not get the chance to see the twenty-second.&lt;/p&gt;
&lt;p&gt;Before, even the summer after the college entrance examination was unimaginable.&lt;/p&gt;
&lt;p&gt;Now, becoming a corporate drone was unimaginable.&lt;/p&gt;
&lt;p&gt;We always step across those thresholds without noticing, then feel a little flattered and a little at a loss.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;My interest in learning arose after I had more or less completed the prescribed educational system and become a so-called member of society. I understood that, if I pursued fields and things that interested me at a pace suited to myself and with methods I liked, I could master knowledge and skills extremely efficiently.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;People who teach themselves almost always become experts, while those from the “academic school”—or those deliberately cultivated and guided, with everything set out on the table for them to consume—often become lost at a certain point and feel unable to make further progress.&lt;/p&gt;
&lt;p&gt;I have tried to leave teachers’ systems behind and study on my own, yet I run into problems too: motivation and feedback. Some people learn because a project requires it. That kind of learning is tiring, but they can quickly and clearly tell how deeply they need to learn. Still, I admire people who are interested in knowledge and technology themselves more: no comparison, no goal, only pure curiosity.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;When I ran a bar, I followed the same principle. Many customers came in. If one person out of ten said, “This place is good. It suits me. I will come again,” that was enough.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I care more about my own feelings; the people who stay do not need to be many, only sincere.&lt;/p&gt;
&lt;p&gt;I try to write my blog and journal with that feeling. I think it is better for me that way, just as fishing alone is better for Arthur Morgan.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Even if the amount of practice declines, do not stop practicing for more than two days. This is a basic rule for building mileage. Muscles are like animals with good memories: as long as you increase the load gradually, they naturally adapt to and bear it.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;When I run continuously, one day of rest feels like an unexpected blessing. But by the next day, laziness has already begun to show. It is not only my muscles slackening off on their own; my thoughts easily talk me into never going out to run again, and then I gradually become comfortable lying down.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Besides talent, if I had to name an important quality for a novelist, I would unhesitatingly name concentration. It is the ability to gather the limited talent one possesses and pour it into the place where it is most needed.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;After concentration, endurance is essential. Even if one can concentrate on writing for three or four hours a day, if one keeps at it for a week and then says, “I am exhausted,” one still cannot write a long work.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;Fortunately, unlike talent, concentration and endurance can be acquired through training. Their capacity can be continually improved.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;When I am extremely idle, I always get up early, read novels and comics, and keep reading until lunch. But I have also had stretches of getting up in the morning and concentrating on one thing: programming, blogging, writing fiction. For a time, I truly felt my focus visibly improving.&lt;/p&gt;
&lt;p&gt;But eventually that growth turns into self-doubt. Every morning feels the same, as if I have fallen into a time loop. Then I stop in retaliation. Breaking a habit feels refreshing at first, but after my brain adjusts to the high dopamine, another kind of boredom sets in.&lt;/p&gt;
&lt;p&gt;I still do not know which way is right or how to spend my mornings. But I think it is necessary to change things every so often and leave myself appropriate “rest days.”&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Running is undeniably captivating: within one’s individual limits, one can burn oneself effectively—even if only a little. That is the true work of running, and a metaphor for living.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I hope to keep running regularly. I hope to keep the habit of focused mornings. Not to keep improving, but as a kind of resistance—to remind myself that I exist in the present and help me better recognize my current situation. To feel grateful for leisure instead of getting lost in aimlessness and boredom.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;At a point when you feel you could keep writing, decisively put down your pen. Then it will be easier to get back into the flow when you begin again the next day. —Hemingway&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;I will go running tomorrow, and if I can, I hope to do the same the day after.&lt;/strong&gt;&lt;/p&gt;
</content:encoded></item><item><title>A Maverick Pig</title><link>https://xnnehang.top/en/posts/a-maverick-pig/</link><guid isPermaLink="true">https://xnnehang.top/en/posts/a-maverick-pig/</guid><description>Reading notes on Wang Xiaobo&apos;s A Maverick Pig</description><pubDate>Sat, 12 Oct 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;My Spiritual Homeland&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;Words are meant to be read and heard, not merely looked at. If looking is what you want, you might as well turn to picture books. Anyone who fails to understand this can only produce textual garbage full of noise. Thought, language, and writing are all of a piece: if the words sound muddled when read aloud, the ideas will be no better.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Wang is talking about fiction here. Recently, while reading short stories, I have found some that seize my attention within two or three lines, while others leave my gaze unfocused even after a page or two, the whole piece remaining hazy by the time I finish it. Later, I began making a point of checking the translator&apos;s name; there are some translators I now skip at a glance. It seems that the writing itself matters a great deal in fiction.&lt;/p&gt;
&lt;p&gt;I find Wang Xiaobo&apos;s writing very easy to focus on. It is easy to quiet down and settle into the right frame of mind.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Spend a lifetime learning art. I studied both the humanities and the sciences. Yet in the classroom, it was my science teachers who mentioned the word &lt;em&gt;art&lt;/em&gt; more often: my chemistry teacher said there was an art to conducting experiments; my computer science teacher said there was an art to programming. They said that knowing how to do something correctly is science, while knowing how to do it well is art. The former has rules for judging truth from falsehood; the latter does not. The essence of art is to make people feel that something is good—even flawless.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;After the college entrance exam, I initially wanted to major in Chinese language and literature, my head full of dreams of writing fiction. But after several twists and turns, I ended up in artificial intelligence. AI—&lt;em&gt;Artificial Intelligence&lt;/em&gt;—at least it still gave me half a claim to &lt;em&gt;Art&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;I also took quite a few online electives in art and literature: Buddhist art, appreciation of the Four Great Classical Novels, ancient Chinese literature, architectural art, and so on.&lt;/p&gt;
&lt;p&gt;Later, though, I realized that these so-called “arts” were merely constructing systems of judgment and understanding. In the terms above, they were concerned with right and wrong, not good and bad. They had attained science, but had not become arts in their own right.&lt;/p&gt;
&lt;p&gt;Seen that way, this accidental turn of events may have been something to be grateful for.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I have always felt that once you have read &lt;em&gt;The Lover&lt;/em&gt;, you know what the art of the modern novel is; once you have read Wang Daoqian&apos;s translated prose, you know what modern Chinese literary language is.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;When I first read this in high school and saw Wang Xiaobo lavish praise on Wang Daoqian&apos;s translation of &lt;em&gt;The Lover&lt;/em&gt;, I immediately went out and bought that edition. It was my first work of French literature, dreamlike and unreal.&lt;/p&gt;
&lt;p&gt;Later, after I lent the book to a female classmate, two more female classmates came to ask whether I had a copy of &lt;em&gt;The Lover&lt;/em&gt;.&lt;/p&gt;
&lt;h2&gt;The Art of Fiction&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;I read essays myself, and sometimes write a few. As I see it, an essay is simply a matter of making an argument: once you see where the reasoning lies, you state it plainly.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;To burden fiction with moral responsibility is, as the Greeks put it, to fasten the saddle onto the head.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;Any art can be known only through its works. Those who like to read only essays, criticism, and summaries will never understand any kind of art.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;So there is really no need for me to spout nonsense unless I cannot help myself. Otherwise, I might as well hold my tongue and keep copying passages. The more I write, the more likely it is to feel affected and contrived.&lt;/p&gt;
&lt;p&gt;Still, reading an essay now and then can be a pleasure. It gives you the feeling of having arrived at a different point of view without having to use your brain.&lt;/p&gt;
&lt;h2&gt;On the Art of Fiction, Starting with &lt;em&gt;The Golden Age&lt;/em&gt;&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;Being positive and aspiring may be a principle for conducting oneself, but it should not be kept on one&apos;s lips at every moment. I believe my proper job is to make my fiction as engaging as possible, not to lace it with deliberate moralizing. My approach to writing is to create works for people who read fiction, not to lecture wayward young people.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Shaping people&apos;s character and the like should be a concern for children&apos;s books. The author&apos;s proper task, and fiction&apos;s proper task, is simply to convey another life, another world. As an extension of my brief life, if that world is rendered with fullness and in concrete form, then the work has already done its job. Moral instruction is not an author&apos;s obligation; drawing insight from the work is the reader&apos;s concern.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;In truth, every book should be interesting. For some books, being interesting is their reason for existing; for some novels, it is the standard they ought to meet. I can remember every interesting book I have read, while with dull ones I cannot even recall the title. But it is not just me: all of us are close to forgetting what &lt;em&gt;interesting&lt;/em&gt; even means.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;What does it mean for something to be interesting? Every work by Xia Da is quite interesting, &lt;em&gt;Song of the Long March&lt;/em&gt; most of all. That is what I think for now.&lt;/p&gt;
</content:encoded></item><item><title>Sahara Stories: Reading Notes</title><link>https://xnnehang.top/en/posts/sahara-stories/</link><guid isPermaLink="true">https://xnnehang.top/en/posts/sahara-stories/</guid><description>Sanmao and José, a desert restaurant, and a record of their marriage.</description><pubDate>Thu, 10 Oct 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;img src=&quot;../../assets/img/covers/sahara-stories.jpg&quot; alt=&quot;Sahara Stories&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Most of my recent reviews are mainly excerpts mixed with my own thoughts, though someone may have noticed that there are only a few pieces for each book. That is because I am not doing elementary-school reading-response homework, writing something for every chapter I finish. Writing takes time, and sorting out my thoughts takes energy. Usually I only write about the first two pieces that move me, at most four; after that, I just read and underline.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;Sanmao (1943–1991)&lt;/p&gt;
&lt;p&gt;Her birth name was Chen Maoping. Since she could not learn to write the character &lt;em&gt;mao&lt;/em&gt;, she renamed herself Chen Ping.&lt;/p&gt;
&lt;p&gt;At thirteen, she ran away to Xiaoliuqiu to have fun; in middle school, she skipped class to read miscellaneous books among the graves.&lt;/p&gt;
&lt;p&gt;Travel and reading were the two brightest stars in her life, entwined with both her greatest happiness and her deepest pain.&lt;/p&gt;
&lt;p&gt;She saw a photograph of the Sahara Desert and felt a homesickness from a previous life, so she decided to move there. José, who had long been in love with her, followed without a second thought.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I first encountered Sanmao while browsing a bookstore in high school. Among a stack of Keigo Higashino books, I found &lt;em&gt;Meteor Shower&lt;/em&gt;. It was a paperback mixed into a pile of hardcovers, conspicuous in its own way, and I liked the cover and its colors.&lt;/p&gt;
&lt;p&gt;After I bought it, I found that it recorded Sanmao’s speeches and interviews. The speeches made me think: this person is so strange—much stranger than I am—but also so interesting.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Sahara Stories&lt;/em&gt; was the second book. During that period, I read only Sanmao, and she later became the first author whose complete works I finished.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Sahara Stories&lt;/em&gt; is also the first book I often recommend to people who do not usually read physical books: my mother, my grandfather, and countless classmates. Very few of them finish it. I do not understand whether they simply do not get Sanmao’s particular kind of strangeness, or whether I am strange too. But through this book, I found a friend with whom I could communicate without words.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;A Restaurant in the Desert&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;The first course was “vermicelli cooked in chicken soup.” José took a sip and asked, “Eh, what is this? Fine Chinese noodles?”&lt;/p&gt;
&lt;p&gt;“Your mother-in-law sent you fine noodles all the way from China? No.”&lt;/p&gt;
&lt;p&gt;“Then what is it? Give me some more—it is delicious.”&lt;/p&gt;
&lt;p&gt;I lifted one strand with my chopsticks. “This is called rain.”&lt;/p&gt;
&lt;p&gt;“Rain?” He froze.&lt;/p&gt;
&lt;p&gt;“This is the first rain of spring. It falls on the high mountains and freezes strand by strand. Mountain people bundle it up, carry it down, and sell it for rice wine. It is not easy to get.”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;After that, he often ate “spring rain,” and to this day he does not know what it is made from. Sometimes I think José was rather silly, and that makes me a little sad.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Sanmao was exceptionally good at Chinese and exceptionally bad at mathematics. Her skill with language was not ordinarily good, and neither was her weakness in math. She was the kind of writer whose essay could make a teacher cry; she wrote so well that I would not feel it excessive to copy out a whole piece.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;A Record of Marriage&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;“Sorry to tell you at the last minute. We did not know in advance that we would be getting married tomorrow. Please forgive us—” José’s telegram was as long as a letter.&lt;/p&gt;
&lt;p&gt;As for me, I used my father’s registered telegram account and wrote: “Sanmao marries tomorrow.” Only a few words.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;It seems Chinese people always sent telegrams that briefly. I had seen notices of bereavement in old books and films too: “Father critically ill. Return at once,” and so on.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“I want to take you to a movie. Tomorrow, you will not be my girlfriend anymore.”&lt;/p&gt;
&lt;p&gt;So we ran to the only fifth-rate desert cinema and watched the excellent &lt;em&gt;Zorba the Greek&lt;/em&gt;, as a farewell to our single days.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I copied out an unusual amount today because I think these two pieces introduce Sanmao and José very well.&lt;/p&gt;
&lt;p&gt;The last couple I found this interesting were Shen Fu and Chen Yun in &lt;em&gt;Six Records of a Floating Life&lt;/em&gt;, but theirs was a separation by death.&lt;/p&gt;
&lt;p&gt;Sanmao’s writing offers readers a pair of eyes. It seems to open another side of the world: full of life, vitality, and humor. Put another way, if I were in that setting, I would see inconvenience and hardship. But Sanmao could show readers the genuinely interesting parts through a magical yet natural style.&lt;/p&gt;
&lt;p&gt;I should learn from her too, whether in style or in that way of observing.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;The Child Bride&lt;/h2&gt;
&lt;p&gt;In a Sahrawi town around the 1970s or 1980s, only men could become doctors. Unmarried women with illnesses involving intimate parts of their bodies would rather die than let a male doctor examine them.&lt;/p&gt;
&lt;p&gt;Many women were married at around ten years old; some even at eight.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;When I reached this part, I suddenly felt something. The world is so large, and perhaps I will never live for a while in a town in the Sahara Desert. The differences between countries are so vast too; perhaps I cannot experience them one by one.&lt;/p&gt;
&lt;p&gt;It is the same across time. I cannot imagine what the night markets of Chang’an in the Tang dynasty were like, or what it was like when a princess went on an outing.&lt;/p&gt;
&lt;p&gt;There is so much I cannot reach: because of distance, because of time. Yet I cannot stop that small curiosity, that small longing.&lt;/p&gt;
&lt;p&gt;And words have shown me so much: Kawabata’s Kyoto and snow country, Mishima’s Song Island, the Athens Haruki Murakami traveled through, Sanmao’s Sahara.&lt;/p&gt;
&lt;p&gt;In animation, the capital of the State of Yuanwu in &lt;em&gt;A Record of a Mortal’s Journey to Immortality&lt;/em&gt; fulfilled a little of my imagined Chang’an. In comics, Li Changge is my princess.&lt;/p&gt;
&lt;p&gt;These are undoubtedly fictional, but the small fragments of truth I catch within fiction move me. I am grateful that novels exist in this world, and grateful for those animated works.&lt;/p&gt;
</content:encoded></item><item><title>Reading Notes on Rashomon</title><link>https://xnnehang.top/en/posts/luoshengmen/</link><guid isPermaLink="true">https://xnnehang.top/en/posts/luoshengmen/</guid><description>Reading notes on Ryūnosuke Akutagawa&apos;s short-story collection, recording passages and impressions worth returning to.</description><pubDate>Thu, 26 Sep 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;img src=&quot;../../assets/img/covers/luoshengmen.jpg&quot; alt=&quot;Rashomon&quot; /&gt;&lt;/p&gt;
&lt;p&gt;September 26&lt;/p&gt;
&lt;p&gt;I had failed to finish long novels like &lt;em&gt;The Razor&apos;s Edge&lt;/em&gt; when rereading them before, so I decided to begin with short stories instead.&lt;/p&gt;
&lt;p&gt;The kappa in the table of contents reminded me of &lt;em&gt;The Girlfriend at the End of the World&lt;/em&gt;, a book that still leaves a very good impression when I think back on it.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;September 27&lt;/p&gt;
&lt;h2&gt;The Nose, Rashomon, In a Grove, Hell Screen&lt;/h2&gt;
&lt;p&gt;I came across Lu Xun’s translations! They did not feel distant at all: they were easy to read and hardly different from more recent translations. Both pieces Lu Xun translated even include short afterwords, discussing Akutagawa and why he chose those works to translate. You really do not see such interesting post-reading notes beneath translated works today. They feel like an exchange of views with the reader. Nowadays translators generally write only one preface at the beginning, which I usually skip. Perhaps translators are no longer expected to speak for themselves; perhaps they worry readers will think they are putting on airs; or perhaps the extra writing does not count toward their fee. =-=&lt;/p&gt;
&lt;p&gt;The detective elements in &lt;em&gt;In a Grove&lt;/em&gt; and &lt;em&gt;Hell Screen&lt;/em&gt; were immensely satisfying. Several of the stories as a whole feel a little like reworkings of old tales: their material already existed, perhaps as folk legends or works by earlier writers, and then the stories and characters are taken out and shown from a new perspective—or adapted into new stories. Lu Xun’s &lt;em&gt;Old Tales Retold&lt;/em&gt; may also have drawn some inspiration from this. [I inferred this from Lu Xun’s little post-reading notes.]&lt;/p&gt;
&lt;p&gt;Akutagawa read so widely. He understood not only Japan, but China as well. A genius, a genius. There really should be more afterwords.&lt;/p&gt;
&lt;p&gt;Did Akutagawa have a book recording his trip to China? Or am I remembering incorrectly? I should look it up later.&lt;/p&gt;
&lt;p&gt;Incidentally, this time I was reading the Dook Media edition.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;Another Side&lt;/p&gt;
&lt;p&gt;Opening a book and getting through the first five pages is truly difficult. I resist it in every possible way. In the end, I tell myself that I can play games after reading ten pages. Only then do I read while listening to music. But after those ten pages, it is as if some magic takes hold: both my reading speed and my ability to enter the book suddenly increase, until I stop more than a hundred pages later. Then I go play games, and even that leaves me feeling refreshed.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;September 28&lt;/p&gt;
&lt;h2&gt;Father, The Monkey, The Life of a Stupid Man&lt;/h2&gt;
&lt;p&gt;Both &lt;em&gt;Father&lt;/em&gt; and &lt;em&gt;The Monkey&lt;/em&gt; reflect an instinct for pity and sympathy. But &lt;em&gt;Father&lt;/em&gt; awakens to it first, while &lt;em&gt;The Monkey&lt;/em&gt; awakens to it later. Placing these two stories next to each other shows real editorial skill.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;The Life of a Stupid Man&lt;/em&gt;, like &lt;em&gt;Hell Screen&lt;/em&gt;, has something of the spirit of a god of creation. But &lt;em&gt;Hell Screen&lt;/em&gt; has a third party objectively record one person’s almost pathological pursuit of art, mixing mystery with hearsay. In the moment when the carriage is burned, he is majestic as a god. Everything seems cut off from him. Interestingly, the fox spirits are used to describe his creative state: when he creates, a group of fox spirits stands behind him, so he writes through the night without stopping and ignores even the daughter he normally dotes on.&lt;/p&gt;
&lt;p&gt;But &lt;em&gt;The Life of a Stupid Man&lt;/em&gt; brings the perspective much closer, focusing throughout on Bakin—the creator—and tracing his psychological changes in great detail. Two points are especially interesting. First, Bakin can remain unmoved by praise for his work, yet criticism immediately puts him on guard. But when he truly looks at the person criticizing him, he suddenly finds he cannot take it personally at all, and his mood abruptly clears. This first reveals a shift in his creative spirit: he is becoming unconcerned with the outside world, though he has not yet reached the peak.&lt;/p&gt;
&lt;p&gt;That peak comes later that night, when he goes home and rereads the drafts he had previously written and revised. They feel dull on rereading, so he can only rewrite them. Yet his inspiration runs dry, and he feels that he may be nothing more than a conceited mediocrity, no different from the people he despises. Then his little grandson—perhaps genuinely, perhaps taught by his parents—comes to him. [Bakin adores the child, and immediately puts down the gloom that had gathered while writing.] The boy says that the Bodhisattva at the temple asked him to bring two sentences: “Work hard. Do not lose your temper.” It is as if Bakin suddenly understands something.&lt;/p&gt;
&lt;p&gt;That night, he begins creating again. At first, his inspiration is like a fine thread of flame that the slightest breath of wind could extinguish. But he carefully shelters it. After three or four lines, then ten or so, his thoughts come in waves like a rising tide. He writes without stopping all night.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The tide in his mind was like the Milky Way racing across the sky, surging out from nowhere. Its force frightened him. What if his body could not bear it? He gripped his pen tightly and reminded himself again and again: “Write with all your strength. If you miss this chance, perhaps you will not be able to write for a long time.”&lt;/p&gt;
&lt;p&gt;Yet that current, like a dim and hazy light, did not slow in the least. Instead, it rushed on dazzlingly, drowning everything and surging toward him in great waves. At last he was completely captured. He forgot everything and moved his pen in the direction of that current, with the force of a violent storm.&lt;/p&gt;
&lt;p&gt;Reflected in his &lt;strong&gt;imperial&lt;/strong&gt; eyes at that moment were neither profit and loss nor love and hate. Praise and blame could no longer move his feelings. There was only an inexplicable joy—or an intoxicating, tragic passion. How could someone who does not understand this passion experience the state of creative absorption? How could they understand the solemn soul of a writer? Look: has “life” not washed away all its dross, like a newly mined ore, and begun to glitter brilliantly before the author’s eyes?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The ending is interesting too. It goes roughly like this:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“Is Father still not asleep?”&lt;/p&gt;
&lt;p&gt;“He must be bent over his writing again.”&lt;/p&gt;
&lt;p&gt;“There is really nothing to be done with him. He cannot even earn much money.”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Reading and creating are much the same. At the beginning, I feel discouraged; but once I enter the state, there is an inexplicable joy, the same kind of feeling as above.&lt;/p&gt;
&lt;p&gt;When I was learning digital painting before, I would also feel a kind of passion after completing a picture. For an instant, I would have the illusion that my whole life had been worth it.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;Another Side&lt;/p&gt;
&lt;p&gt;This morning, beginning was difficult in the same way. But the first story, &lt;em&gt;Father&lt;/em&gt;, quickly brought me into the right state, like a sudden jolt.&lt;/p&gt;
&lt;p&gt;Interestingly, I do most of my reading while eating. After finishing &lt;em&gt;Father&lt;/em&gt;, I went out for breakfast and read while slowly eating rice porridge. I became especially absorbed in it. It was also the first time I had felt like I was truly enjoying a weekend morning, or simply felt leisurely on a day without classes.&lt;/p&gt;
&lt;p&gt;I also noticed something: changing environments can make a great difference compared with staying beside a source of temptation—the computer.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;September 29&lt;/p&gt;
&lt;h2&gt;Oranges, The Dragon, Scallions&lt;/h2&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;em&gt;Oranges&lt;/em&gt; depicts a person changing from nihilism back to reality, from finding everything dull at first to feeling life again. It is worth rereading and saving away, then bringing out again when I feel something similar.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;The Dragon&lt;/em&gt;: even if something begins as a prank, when countless people believe in it and hold hope for it, the thing receives a response from the gods. There is no metaphor about public opinion or anything like that; instead, it shows the beauty of wishes.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Scallions&lt;/em&gt; is a novel with an extremely strong visual quality. Its ending is very interesting, and it gives the feeling of suddenly waking up, abruptly pulling reality into fantasy. Worth saving and rereading.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;Another Side&lt;/p&gt;
&lt;p&gt;I was reading during class this morning. In the past, I always felt I could not get into a good state while reading fiction in class. But in fact, much of that came from the wrong frame of mind. I thought the teacher’s microphone was noisy, and that it therefore disturbed me. The logic is actually reversed. If I change my thinking—if I tell myself that I ought to listen to the teacher, but would rather read fiction, and that the teacher is not targeting me—then I instead feel grateful, and the irritation and anger disappear.&lt;/p&gt;
&lt;p&gt;Put another way, this is the difference between “should” and “want.”&lt;/p&gt;
&lt;p&gt;For example, a husband may believe beforehand that, because he works hard, his wife &lt;strong&gt;should&lt;/strong&gt; have dinner ready. If he comes home late to a dim dining room and an empty table, a nameless anger immediately rises in him. Even if a meal has been prepared, he feels no extra gratitude; instead, he may become sensitive to whether it is too hot or cold, too salty or bland.&lt;/p&gt;
&lt;p&gt;But if he gives up the idea that his wife “should” do this, and assumes that it does not matter whether anyone cooks—he can always eat out—then receiving a message from his wife saying, “I got off work early today. I’ll make dinner,” fills him with warmth and an inexplicable joy.&lt;/p&gt;
&lt;p&gt;It is only a difference of thought, but my old way of thinking was not quite right.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;Kappa, The Life of a Stupid Man, A Fool’s Life, Life&lt;/h2&gt;
&lt;p&gt;In the final few stories of the collection, Akutagawa’s mental state seems no longer very good. The editor has arranged these pieces from light to heavy; perhaps the earliest sign appeared in &lt;em&gt;Oranges&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;It seems that eight or nine out of every ten Japanese writers I know died by suicide. Kawabata, Dazai, Akutagawa, Mishima?&lt;/p&gt;
&lt;p&gt;The earlier sections of the collection keep creation and life quite separate. Later, you can already feel life intruding on creation. Since I had read other translations of these works before, I only skimmed these few.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“Life is not worth a single line of Baudelaire.”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;At last, I know where that person’s profile quote came from.&lt;/p&gt;
&lt;p&gt;Another interesting part:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;He was walking through a field overgrown with foxtail grass with a university student.&lt;/p&gt;
&lt;p&gt;“You still have a strong desire to live, do you not?”&lt;/p&gt;
&lt;p&gt;“Yes… but you too…”&lt;/p&gt;
&lt;p&gt;“But I do not. I have only the desire to create.”&lt;/p&gt;
&lt;p&gt;“The desire to create is also a desire to live.”&lt;/p&gt;
&lt;p&gt;He did not answer. At some point, a volcano had come clearly into view over the red spikes in the field. He felt a little envious of that volcano, though he could not say why…&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I hope everyone like this can find the redemption that appears in &lt;em&gt;Oranges&lt;/em&gt;.&lt;/p&gt;
</content:encoded></item><item><title>From Frieren: Beyond Journey&apos;s End to Psychological Compulsion</title><link>https://xnnehang.top/en/posts/frieren-ocd/</link><guid isPermaLink="true">https://xnnehang.top/en/posts/frieren-ocd/</guid><description>On viewing rituals and procrastination, and the compulsive resistance that keeps one from beginning.</description><pubDate>Mon, 09 Sep 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Snacks + a drink + nighttime = happiness.&lt;/p&gt;
&lt;p&gt;Like Umaru, watching anime or a film ought to have a little ritual to it.&lt;/p&gt;
&lt;p&gt;In reality, though, that ritual kept me circling around instead of getting into bed. [I watch in bed.]&lt;/p&gt;
&lt;p&gt;In the end, I watched for only forty minutes, from 10:20 to 11:00.&lt;/p&gt;
&lt;p&gt;But after playing basketball today, I got home at 7:20. I put off showering until 8:30. I could not decide whether to play games with my classmates, so I spent an hour browsing Bilibili instead. It was 9:00 after I showered, but I still did not get into bed. I watched the beginning of my &lt;em&gt;Red Dead Redemption&lt;/em&gt; playthrough and lingered until 10:20.&lt;/p&gt;
&lt;p&gt;I run into this kind of procrastination often. It is undoubtedly a form of resistance.&lt;/p&gt;
&lt;p&gt;At the end of the semester before last, one of my roommates had one fewer exam than I did, so I stayed in the dorm alone for three extra days.&lt;/p&gt;
&lt;p&gt;On two of those nights [it was exam week, so there were no classes], I turned off the lights and got into bed at seven on the dot to watch &lt;a href=&quot;https://movie.douban.com/subject/35755307/&quot;&gt;&lt;em&gt;Throne of Seal&lt;/em&gt;&lt;/a&gt;. I watched sixty episodes in two days. That atmosphere is something I could never recreate.&lt;/p&gt;
&lt;p&gt;Even now, my viewing experience is still wonderful. There are funny moments and profound ones—and, it must be said, lying down makes it much easier to slip into the experience than watching while seated.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/img/frieren-ocd/202409092313304.jpg&quot; alt=&quot;Watching Frieren while lying down&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/img/frieren-ocd/202409092313909.jpg&quot; alt=&quot;Frieren&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/img/frieren-ocd/202409092313529.jpg&quot; alt=&quot;Frieren&quot; /&gt;&lt;/p&gt;
&lt;p&gt;I did not take more pictures in many places, but even in just over forty minutes, the experience was still very good.&lt;/p&gt;
&lt;p&gt;Yet the resistance I mentioned earlier is something that needs to be overcome. I sometimes encounter it while working on projects too: once I get into the rhythm, I can enjoy myself, but a kind of compulsion keeps me from taking the first step.&lt;/p&gt;
&lt;h2&gt;On Compulsion&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;There is a man who is going to travel somewhere the next day. The night before, he calls women he knows who live there and wants to invite any one of them to dinner. (A sexual invitation.) Only after every one of them has rejected him does he let out a long breath and say, “Now I finally have time to open a bottle of wine and read by myself.”&lt;/p&gt;
&lt;p&gt;In fact, he has plenty of time like this, but he cannot refuse the impulse to make those sexual invitations. Only when he encounters an irresistible force can he escape from it.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;My experience is that it is enough to stop thinking and simply take the first step. Thinking is the greatest resistance, because all it considers are excuses.&lt;/p&gt;
</content:encoded></item><item><title>After Forbidden City Cop</title><link>https://xnnehang.top/en/posts/daneimitan-00fa/</link><guid isPermaLink="true">https://xnnehang.top/en/posts/daneimitan-00fa/</guid><description>Notes on Forbidden City Cop: its familiar kind of love and its use of light and composition.</description><pubDate>Sat, 07 Sep 2024 00:00:00 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;I have been changing the style of these post-viewing notes lately. I no longer want to keep proving and investigating some supposed principle over and over; it is exhausting, and I need a rest. Here I simply want to note the interesting parts, keep things light, and avoid making the reader think too hard. If possible, I would like to be a little humorous. Compared with serious, meticulous arguments, humorous language is better at helping people relax.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This film had been on hold for a long time. It was still my first time watching it.&lt;/p&gt;
&lt;p&gt;Before, I had put it off partly because I could not find a copy, and partly because the two “old ladies” on the poster were rather discouraging.&lt;/p&gt;
&lt;p&gt;But once I started watching, I realized they were familiar faces after all: Peach Blossom from &lt;em&gt;Ashes of Time&lt;/em&gt;, and Xiao Longnü!&lt;/p&gt;
&lt;p&gt;The makeup is dramatically different, especially for Xiao Longnü. She originally looked like this:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/img/daneimitan-00fa/202409072253935.png&quot; alt=&quot;Xiao Longnü&apos;s classic appearance&quot; /&gt;&lt;/p&gt;
&lt;p&gt;But in this film, she looks like this:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/img/daneimitan-00fa/202409072254982.jpg&quot; alt=&quot;Xiao Longnü in Forbidden City Cop&quot; /&gt;&lt;/p&gt;
&lt;p&gt;That is not how you looked in Yang Guo’s arms:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/img/daneimitan-00fa/202409072300006.png&quot; alt=&quot;Xiao Longnü in The Return of the Condor Heroes, 1&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/img/daneimitan-00fa/202409072300677.png&quot; alt=&quot;Xiao Longnü in The Return of the Condor Heroes, 2&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Had there not been a close-up of her eyes and brows midway through the film, I would not have recognized her as Xiao Longnü.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/img/daneimitan-00fa/202409072302785.jpg&quot; alt=&quot;Close-up of her eyes and brows&quot; /&gt;&lt;/p&gt;
&lt;p&gt;When I watched &lt;em&gt;The Return of the Condor Heroes&lt;/em&gt; in the past, I always thought Auntie’s eyes were especially profound. Seeing them here suddenly brought that back to me.&lt;/p&gt;
&lt;p&gt;Beauty is dynamic. Compared with the two old ladies on the poster, his wife in the film is simply adorable.&lt;/p&gt;
&lt;p&gt;Writing a long review takes a great deal of effort unless I truly have something to say. Right now, I do not.&lt;/p&gt;
&lt;p&gt;So I will just note the parts worth rewatching and the bits I found interesting.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/img/daneimitan-00fa/202409072307268.jpg&quot; alt=&quot;Screenshot from a classic scene&quot; /&gt;&lt;/p&gt;
&lt;p&gt;The complete exchange goes like this:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;— “Hey, are you hungry? I’ll cook you a bowl of noodles.”&amp;lt;br&amp;gt;
&amp;lt;br&amp;gt;
“How did you know I always hide under the table?”&amp;lt;br&amp;gt;
“You hide under the table every time. How could I not know? Please use your brain a little. Find a few new places to hide, so I can have some novelty for once, all right?”&amp;lt;br&amp;gt;
“But if I do not hide under the table, I am afraid you will not be able to find me.”&amp;lt;br&amp;gt;
“Ah! Ah! I cannot stand you. Please do not be like this. I am begging you, wife. Do not be like this. Thank you, thank you, thank you...&amp;lt;br&amp;gt;
Hey! I am only flesh and blood. You scold me like this every time. I do not know when I will finally be unable to bear it anymore.”&amp;lt;br&amp;gt;
“If you cannot bear it, then leave.”&amp;lt;br&amp;gt;
“I am going to take a bath.”&amp;lt;br&amp;gt;
“I told you to leave!”&amp;lt;br&amp;gt;
“Hey, are you hungry? I’ll cook you a bowl of noodles.”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This kind of cliché can be moving sometimes. It makes me feel that the people in the film are as cliché as I am—or rather, that they feel real.&lt;/p&gt;
&lt;p&gt;Their relationship is worth revisiting.&lt;/p&gt;
&lt;p&gt;Another part is the intercut sequence between the Emperor being attacked while traveling and the two of them going out together: knocking on watermelons, tearing chicken, squeezing eggs. It creates a comic atmosphere, but it also seems to carry a deeper metaphor. Hong Kong films are always full of faint, half-seen metaphors. You can interpret them, or you can ignore them. Whether they are truly there does not seem important to the plot, but it somehow feels important to me.&lt;/p&gt;
&lt;p&gt;I am being cryptic because I do not want to spend the energy working it all out. I need to recuperate for a while. The parts worth revisiting should go on the Time Machine watchlist instead.&lt;/p&gt;
&lt;h2&gt;Screenshots for the Pervert&lt;/h2&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/img/daneimitan-00fa/202409072318942.jpg&quot; alt=&quot;Light and composition, 1&quot; /&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Under this filter, she has a little of Wang Zuxian’s Nie Xiaoqian about her. In the same setting, the lighting is drastically different between two shots, yet it does not make me uncomfortable. Instead, it creates a sense of opposing forces. Few directors today would dare use lighting this way. Here is the same setting:&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/img/daneimitan-00fa/202409072319205.jpg&quot; alt=&quot;Light and composition, 2&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/img/daneimitan-00fa/202409072320437.jpg&quot; alt=&quot;Light and composition, 3&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/img/daneimitan-00fa/202409072320509.jpg&quot; alt=&quot;Light and composition, 4&quot; /&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Composition. I pulled out my phone to take a picture in an instant, but it did not focus. Or rather, because my photography skills are poor, most of these did not focus properly.&amp;lt;br&amp;gt;
&amp;lt;br&amp;gt;
And because of my “image host,” I had to compress them once more. I expect every picture now has a slightly mosaic-like quality.&lt;/p&gt;
&lt;/blockquote&gt;
</content:encoded></item><item><title>After A Chinese Odyssey Part Two: Cinderella</title><link>https://xnnehang.top/en/posts/dasheng-quqin/</link><guid isPermaLink="true">https://xnnehang.top/en/posts/dasheng-quqin/</guid><description>Thoughts after A Chinese Odyssey Part Two: Cinderella: the value recognized only after loss, and Sun Wukong&apos;s human side.</description><pubDate>Sun, 01 Sep 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Let me first put forward two propositions:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;If Zixia possessed Zhu Bajie, could I accept it? [Though in the film it is Qingxia who possesses him.]&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Is the value we recognize only after losing something exaggerated? Or is it genuinely difficult for us to notice the value of what we possess?&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;And one discussion outside the topic:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Would &lt;em&gt;Cinderella&lt;/em&gt; be seen as a distortion of the original &lt;em&gt;Journey to the West&lt;/em&gt;? Is that a conspiracy theory? Why do I not reject &lt;em&gt;Cinderella&lt;/em&gt; as I reject &lt;em&gt;Black Myth: Wukong&lt;/em&gt;, but accept it instead?&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Reality Is Not a Fairy Tale&lt;/h2&gt;
&lt;p&gt;I previously mentioned in [[After A Chinese Odyssey Part One: Pandora&apos;s Box]] that I am an ordinary person. A large part of my motivation for watching films comes from female characters, contrast cuteness, adorableness, and intelligence. I came half for that one look from Zixia [Athena Chu], a scene I have always remembered.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/img/dasheng-quqin/202408302313483.jpeg&quot; alt=&quot;Zixia&apos;s classic look&quot; /&gt;&lt;/p&gt;
&lt;p&gt;So if you insist on asking whether I could still accept Zixia becoming Zhu Bajie, I think I probably could not.&lt;/p&gt;
&lt;p&gt;But I previously argued against myself. In [[After The God of Cookery]] I wrote:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;When Stephen is first kissed by Mok, he frantically wipes his mouth in front of a mirror. Even after learning from people on the street that she had liked him for a long time, Stephen still cannot accept it. In truth, my own mind initially followed his. I wavered a little, but not enough to shake the foundation of my attachment to looks.&lt;/p&gt;
&lt;p&gt;Only when the thing itself was torn open and shown to me did I finally, in an instant, escape that pit of appearances. A wave of regret came over me, and I remembered her earlier bowl of rice and the time she shielded a knife with her hand. Only then did I truly recognize what was in my heart. Being overly concerned with looks is an illness. Being born to prefer cute things is not wrong; cute things make people feel close to them and fond of them. But if we stop at a first impression, perhaps we can never say that we have truly come to know someone further. The director tears this truth open for us through Mok&apos;s “death.” It is masterful, with no unnecessary explanation: a slip of paper, a song, and finally a bowl of rice. Nothing is simply handed over at once; it advances layer by layer.&lt;/p&gt;
&lt;p&gt;I can accept mediocrity. I can accept flaws. But I still have my limits, and this is one I cannot bear.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Unless an existing thing is torn open and shown to someone, that person finds it difficult to truly face what they really feel inside. Just as Zixia is captured and waits for her destined hero to arrive on seven-colored clouds and marry her, Joker is elsewhere preparing a wedding with Jingjing.&lt;/p&gt;
&lt;p&gt;Jingjing later runs away because she has seen Joker&apos;s heart: she is no longer the person he loves most.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/img/dasheng-quqin/202408302319761.jpeg&quot; alt=&quot;Jingjing sees Joker&apos;s heart&quot; /&gt;&lt;/p&gt;
&lt;p&gt;The words of Patriarch Puti elsewhere make this clear as well.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“You kept calling Jingjing, Jingjing in your sleep—eighty-eight times.”&lt;/p&gt;
&lt;p&gt;“Really?”&lt;/p&gt;
&lt;p&gt;“Oh, and another name: Zixia. You called that seven hundred and eighty-four times first.”&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;“Last night you called Zixia&apos;s name seven hundred and eighty-five times. One more than before.”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Meanwhile, after putting on the Golden Hoop, Ma Lau [the Cantonese pronunciation of “monkey”] refuses to acknowledge Zixia. He insists that he is the Great Sage Equal to Heaven, Sun Wukong.&lt;/p&gt;
&lt;p&gt;Though he has the memories and even carries Zixia&apos;s bracelet, he still denies it absolutely.&lt;/p&gt;
&lt;p&gt;Only after Zixia blocks Bull King with her body and falls does he hold Zixia&apos;s hand tightly. But the more he does so, the harder the hoop tightens. Its tightening cannot be hidden.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Answer to proposition one:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;People can never fully recognize their own hearts. They often deceive themselves unconsciously, or have some bitter reason or another.&lt;/li&gt;
&lt;li&gt;Perhaps only after losing her would one know the weight of that Zixia who possessed Zhu Bajie.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The camera returns to the first time Joker pulls out the Purple-Green Sword. Zixia asks him to kiss her, but he ignores her, thinking she is being unreasonable or simply not taking it seriously.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/img/dasheng-quqin/202408302330261.jpeg&quot; alt=&quot;Joker first draws the Purple-Green Sword&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Joker never gives her that kiss in the end.&lt;/p&gt;
&lt;p&gt;Perhaps that is what he owes her.&lt;/p&gt;
&lt;p&gt;In &lt;em&gt;Pandora&apos;s Box&lt;/em&gt;, he is the one who takes the initiative, but loses it immediately afterward.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/img/dasheng-quqin/202408302332805.jpeg&quot; alt=&quot;Joker and Jingjing&quot; /&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Joker and Jingjing&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;But in &lt;em&gt;Cinderella&lt;/em&gt;, Joker never holds Zixia like that from beginning to end. After becoming Ma Lau, he cannot even hold her hand.&lt;/p&gt;
&lt;p&gt;Yet after Ma Lau travels through time again using Pandora&apos;s Box, he meets another pair of “Zixia” and “Joker.”&lt;/p&gt;
&lt;p&gt;This “Joker” is not proactive either.&lt;/p&gt;
&lt;p&gt;And this time Ma Lau possesses “Joker.”&lt;/p&gt;
&lt;p&gt;He returns Joker&apos;s kiss to Zixia.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/img/dasheng-quqin/202408302336990.jpeg&quot; alt=&quot;Ma Lau possesses Joker and returns Zixia&apos;s kiss&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Proposition two:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;I now find this proposition strange. It is like saying that separation is sad because separation exaggerates the sadness of separation.&lt;/p&gt;
&lt;p&gt;Let us divide this into two stages.&lt;/p&gt;
&lt;p&gt;One is before loss, and one is after loss.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Before loss&lt;/strong&gt;: although Joker unconsciously repeats Zixia&apos;s name so many times in his dreams, in reality he stubbornly refuses to admit that he likes her and instead prepares to marry Jingjing.&lt;/p&gt;
&lt;p&gt;When Zixia is not beside him, I think deliberately ignoring the value of something like this produces a similar restless anxiety. After Zixia is captured, Joker often loses his temper at Puti and the others, saying that what he feels for Zixia is only guilt for having abandoned her.&lt;/p&gt;
&lt;p&gt;When Zixia is beside him, Joker truly does not recognize it. He really believes he likes Jingjing more. Yet sometimes he vaguely feels that something is wrong. So unless one asks the true heart from within, as Zixia or Jingjing does, one will not know. When we possess something, Joker—or I—most easily ignores what the heart truly thinks of it.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;After loss&lt;/strong&gt;: does sadness exaggerate the original value of something, creating the feeling that after losing it, one has nothing at all?&lt;/p&gt;
&lt;p&gt;It does, if we frame the question that way. As mentioned before, before loss, one usually cannot recognize the value something beside them has for their true heart. It is easy to feel that it was all one had.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What remains besides what was lost?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;If the director had stopped only with Zixia—if Ma Lau simply went mad after losing her—then the film would have fallen into an overworked cliché. I discussed this when talking about love as a theme in [[After A Chinese Odyssey Part One: Pandora&apos;s Box]].&lt;/p&gt;
&lt;p&gt;But Ma Lau&apos;s attitude afterward is different. Wearing the Golden Hoop means he cannot indulge desire, but it does not mean Ma Lau no longer has desire; the tightening hoop when Zixia dies proves that. Some people overinterpret this and assume that it is one thing for Joker to date a demon, but that after becoming Sun Wukong, remaining unable to let go of emotion would misunderstand Sun Wukong.&lt;/p&gt;
&lt;p&gt;Here I need to explain a little. Their group is still on the road west; they have not obtained the scriptures or achieved fruition. When Tang Sanzang passes through the Kingdom of Women, he even says:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“In this life I have already promised myself to the imperial brother and the Buddha.” [That is, he promised Emperor Tang that he would seek scriptures in the West.]&lt;/p&gt;
&lt;p&gt;“If there is another life…” [This itself shows that Tang Sanzang&apos;s heart was moved. Far from damaging his characterization, it makes him fuller. It undeniably shows that Tang Sanzang is human. Even with profound Buddhist law and lotus flowers coming from his mouth, he is still human.]&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I think Sun Wukong is similar. Zixia is his ordeal in the Kingdom of Women. Tang Sanzang lets go through his own strength, which is clearly more elevated. Sun Wukong, meanwhile, says farewell by pretending not to know her and through death.&lt;/p&gt;
&lt;p&gt;But the scene of Zixia&apos;s death, together with the kiss that Sun Wukong gives Zixia after possessing Joker in another time, makes me feel that Joker is one side of Sun Wukong, while Sun Wukong too is a human being—not a scripture-seeking machine without emotion, desire, anger, or grievance, one who cannot feel wronged even when excluded. And the film never denies the legitimacy of the journey west, or its positive effect on Sun Wukong. After returning the kiss through possession, Sun Wukong finally looks at them on the tower, then catches up with his master. It is as though he has let go of every attachment, and from then on devotes himself wholeheartedly to Buddhism.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Proposition three:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;So in the end, Sun Wukong does not feel disparaged. It instead resembles an ordeal in the Kingdom of Women. After obtaining the scriptures and attaining fruition, that is ultimately still wrapped in people&apos;s beautiful imagination. Whether, after becoming the Victorious Fighting Buddha, Sun Wukong must cut off his Joker side and become entirely emotionless and desireless is part of people&apos;s beautiful imagination of immortals; I cannot judge it. But I at least think that whoever a person is in reality, they are always human first.&lt;/p&gt;
&lt;p&gt;Notes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Ma Lau: the Cantonese pronunciation of “monkey.” I use it here to prevent people from taking this out of context and saying that Sun Wukong simply cannot let go. I only change Ma Lau back to Sun Wukong after Sun Wukong lets go; only then, perhaps, can he be called Wukong.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Screenshots from an LSP:&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;Athena Chu&apos;s beauty is dynamic.&lt;/p&gt;
&lt;p&gt;When I try to capture it in screenshots, seven or eight tenths of it are lost.&lt;/p&gt;
&lt;p&gt;Beauty is not in facial features or anything like that, but in a spirit overflowing from the eyes.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/img/dasheng-quqin/202408310904430.jpeg&quot; alt=&quot;Athena Chu 1&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/img/dasheng-quqin/202408310906218.jpeg&quot; alt=&quot;Athena Chu 2&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/img/dasheng-quqin/202408310906206.jpeg&quot; alt=&quot;Athena Chu 3&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/img/dasheng-quqin/202408310906092.jpeg&quot; alt=&quot;Athena Chu 4&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/img/dasheng-quqin/202408310907563.jpeg&quot; alt=&quot;Athena Chu 5&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/img/dasheng-quqin/202408310907269.jpeg&quot; alt=&quot;Athena Chu 6&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/img/dasheng-quqin/202408310907812.jpeg&quot; alt=&quot;Athena Chu 7&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/img/dasheng-quqin/202408310908110.jpeg&quot; alt=&quot;Athena Chu 8&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/img/dasheng-quqin/202408310908593.jpeg&quot; alt=&quot;Athena Chu 9&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/img/dasheng-quqin/202408310909534.jpeg&quot; alt=&quot;Athena Chu 10&quot; /&gt;&lt;/p&gt;
</content:encoded></item><item><title>After Vampires&apos; Melody</title><link>https://xnnehang.top/en/posts/vampires-melody/</link><guid isPermaLink="true">https://xnnehang.top/en/posts/vampires-melody/</guid><description>Thoughts after finishing Vampires&apos; Melody: romanticism at its most extreme.</description><pubDate>Sun, 01 Sep 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;After Vampires&apos; Melody&lt;/h2&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/img/vampires-melody/202409010944015.jpg&quot; alt=&quot;Title screen&quot; /&gt;&lt;/p&gt;
&lt;p&gt;It had been a long time since I last played a galgame. I have not actually played that many, though saying that makes it sound as if I have.&lt;/p&gt;
&lt;h2&gt;The Game Experience&lt;/h2&gt;
&lt;p&gt;There is a branch map, so you can see which choices cause branches. The ending is linear, and most choices along the way lead to bad endings.&lt;/p&gt;
&lt;p&gt;Only the final choice seems to lead to two endings.&lt;/p&gt;
&lt;p&gt;So this was friendly to me. I do not really like many branching routes; I like this kind of work with a main line. One heroine is a plus: rather than spending effort shaping every character, it is better to write one character well all the way through. A lightly tsundere heroine is a plus too. Tsundere heroines have been out of fashion for many years, so I did not expect to meet one here.&lt;/p&gt;
&lt;p&gt;There is also the issue of a Chinese game with Japanese voice acting. At first I felt that the voice work was not very professional; it sometimes sped up or slowed down, with pauses that were too long.&lt;/p&gt;
&lt;p&gt;I am grateful to the developers for hiring Japanese voice actors even with a limited budget. Even if the Japanese voice acting is not natural, I do not feel embarrassed. But if it were Chinese voice acting, I would probably play with the sound off.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The choices and some of the atmosphere are thrilling. I do not read guides, so I often felt as if I were walking a tightrope. Sometimes it was even more immersive than a horror film.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/img/vampires-melody/202409010925211.jpg&quot; alt=&quot;A tense moment in the game&quot; /&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I have to say: the character art for the male characters in this game is rather casual. Except for the protagonist.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Perhaps because of that sense of horror, some of the game’s flaws do not seem as obvious or exposed.&lt;/p&gt;
&lt;h2&gt;The Story&lt;/h2&gt;
&lt;p&gt;Romanticism at its most extreme: the Earth and Sky ending.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/img/vampires-melody/202409010926845.jpg&quot; alt=&quot;The Earth and Sky ending&quot; /&gt;&lt;/p&gt;
&lt;p&gt;I went straight for the Earth and Sky ending, dying twice in the first two chapters along the way =-=.&lt;/p&gt;
&lt;p&gt;Several choices made my heart pound. Playing this visual novel was more nerve-racking than &lt;em&gt;Death Stranding&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;After experiencing that ending, all I could feel was extreme romance.&lt;/p&gt;
&lt;p&gt;I have heard that in other world lines, humanity launches a nuclear war. The rockets streaking across the sky in the background of my ending are weapons of war.&lt;/p&gt;
&lt;p&gt;But from my perspective, apart from máoxuèwàng and the person in front of me, nothing mattered. The rockets were only background scenery. Romanticism at its most extreme.&lt;/p&gt;
&lt;p&gt;P.S. There seems to be an epilogue, a story ten years later, but I skipped it. That only intensified the romance; I ignored the one remaining touch of reality.&lt;/p&gt;
&lt;p&gt;Everything stopped abruptly at that miraculous moment.&lt;/p&gt;
&lt;h2&gt;Fanservice Screenshots&lt;/h2&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/img/vampires-melody/202409010931727.jpg&quot; alt=&quot;Fanservice screenshot 1&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/img/vampires-melody/202409010931860.jpg&quot; alt=&quot;Fanservice screenshot 2&quot; /&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;This seems to be the same CG as another ending, but I saw it earlier.&lt;/p&gt;
&lt;p&gt;You have to consider that players may not know Natsume Soseki’s “the moon is beautiful” confession trope, or have watched the anime &lt;em&gt;Tsuki ga Kirei&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;But this scene is romantic to me too.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/img/vampires-melody/202409010933718.jpg&quot; alt=&quot;Fanservice screenshot 3&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/img/vampires-melody/202409010933608.jpg&quot; alt=&quot;Fanservice screenshot 4&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/img/vampires-melody/202409010934497.jpg&quot; alt=&quot;Fanservice screenshot 5&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/img/vampires-melody/202409010934234.jpg&quot; alt=&quot;Fanservice screenshot 6&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;Epilogue&lt;/h2&gt;
&lt;p&gt;I will borrow a classmate’s post here.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/img/vampires-melody/202409010936944.jpg&quot; alt=&quot;Screenshot of a classmate&apos;s post&quot; /&gt;&lt;/p&gt;
&lt;p&gt;A galgame player’s capacity for wishful thinking is like a vampire: the longer they live, the stronger it grows. Yet I still find that galgames are true love, even though I barely played any during summer vacation.&lt;/p&gt;
&lt;p&gt;And following up on my previous answer, I wrote in [[We Who Have No Tomorrow Fell in Love Yesterday]]:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Something I wrote during the last winter break.&lt;/p&gt;
&lt;p&gt;And summer break is almost here. Will people learn their lesson, or remain stubborn?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I really did remain stubborn. My original vision for summer vacation was big books + galgames + films.&lt;/p&gt;
&lt;p&gt;But I did not read a single big book. I played only one galgame. I watched films only intermittently. Meanwhile, I did not skip a single day of online games. How is such a habit, regular to the extreme, established and sustained?&lt;/p&gt;
</content:encoded></item><item><title>After A Chinese Odyssey Part One: Pandora&apos;s Box</title><link>https://xnnehang.top/en/posts/yueguang-baohe/</link><guid isPermaLink="true">https://xnnehang.top/en/posts/yueguang-baohe/</guid><description>Thoughts after Pandora&apos;s Box: love as a theme, smallness, and the scope of a work.</description><pubDate>Thu, 29 Aug 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;After &lt;em&gt;Pandora&apos;s Box&lt;/em&gt; — Are films that take romantic love as their subject clichéd, and how might their bad effects arise?&lt;/h2&gt;
&lt;p&gt;Let me begin by putting forward three propositions:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Compared with a work centered on romantic attachments and one centered on the proper path of obtaining scriptures or inheriting a will, does the former fall into cliché or begin with an inferior intention?&lt;/li&gt;
&lt;li&gt;Are small domestic concerns and feelings for the nation inherently opposed?&lt;/li&gt;
&lt;li&gt;How should we position them, and what is “scope”? What kinds of works cannot be forgiven, and what kinds can be accepted?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The person writing this is not a professional. If you expect a dialectic full of professional terms, I cannot provide it.&lt;/p&gt;
&lt;p&gt;To solve the first question, we must first answer: can people avoid being ordinary?&lt;/p&gt;
&lt;h2&gt;Can People Avoid Being Ordinary?&lt;/h2&gt;
&lt;p&gt;As far as I know, most people cannot.&lt;/p&gt;
&lt;p&gt;What mainly kept me watching &lt;em&gt;Pandora&apos;s Box&lt;/em&gt; was Spider Woman&apos;s looks =-= and the adorable Karen Mok. The liveliness of the role she plays exceeds Chingmy Yau&apos;s; every smile and glance moves the heart. Then there is that they are both demons, the transformation jokes, and the contrast that makes the contrast cute rather than tiring. When viewers may be approaching comedy fatigue and their threshold for laughter has risen, the director also lets the characters settle and deepen. Suddenly there is depth—for example, when Spider Woman calls out “Nanny,” and the way Uncle Tat looks at her in that moment.&lt;/p&gt;
&lt;p&gt;As for depth, I put all my attention on Uncle Tat. Earlier, during the Spider Woman&apos;s fight, she asks Uncle Tat, controlled by the Bewitching Mind spell:&lt;/p&gt;
&lt;p&gt;“Are you all right? [nei mou si ma]”&lt;/p&gt;
&lt;p&gt;Uncle Tat&apos;s response is, “Even in a crisis like this, she still remembers to care about me. There is no way around it: I must love her for ten thousand years.”&lt;/p&gt;
&lt;p&gt;Some of that may not be the original line, but “love her for ten thousand years” certainly is.&lt;/p&gt;
&lt;p&gt;I admire the nonsensical humor and comic rhythm of most Stephen Chow films, such as &lt;em&gt;Fight Back to School&lt;/em&gt;. A single step too far becomes excessive. It is as though only Stephen Chow can make nonsense comedy feel natural to me; other actors always seem awkward. The director knows when to joke and when to become serious. That rhythm cannot be learned; there is no rule for it, only a complete grasp of the audience&apos;s heart.&lt;/p&gt;
&lt;p&gt;So is not every nonsensical film that fits your heart also the director&apos;s heartbeat synchronizing with yours—a confession of sorts?&lt;/p&gt;
&lt;p&gt;I have wandered off topic.&lt;/p&gt;
&lt;p&gt;I cannot avoid being ordinary. As I said above, those things are what keep me watching. I have not severed a single one of the seven emotions and six desires; I am so ordinary that I also have a fondness for films that appropriately cater to that ordinariness.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/img/yueguang-baohe/202408291224907.jpeg&quot; alt=&quot;Spider Woman 1&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/img/yueguang-baohe/202408291224146.jpeg&quot; alt=&quot;Spider Woman 2&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/img/yueguang-baohe/202408291225557.jpeg&quot; alt=&quot;Spider Woman 3&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/img/yueguang-baohe/202408291226632.jpeg&quot; alt=&quot;Spider Woman 4&quot; /&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;This look back reminds me of someone: Cheng Ying.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/img/yueguang-baohe/202408291227795.jpeg&quot; alt=&quot;Spider Woman 5&quot; /&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The expression on the one at the far left is very cute. Especially after watching &lt;em&gt;The King of Comedy&lt;/em&gt;, the contrast is even cuter.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I may put more at the end, so I will not add too many here.&lt;/p&gt;
&lt;p&gt;I am an ordinary person, so I do not think it is a problem for a work to catch my attention through romantic love and advance the plot through it. On the contrary, I welcome it.&lt;/p&gt;
&lt;p&gt;And &lt;em&gt;A Chinese Odyssey&lt;/em&gt; is not deliberate about it. It never makes me feel that love is the most important thing, that everything is discussing it, that nothing can work without it. I have seen films that do that—&lt;em&gt;White Snake&lt;/em&gt;, for example, which writes love too forcefully. Once love is removed, what is left? Overemphasizing romantic love and having nothing but romantic attachments are what make people feel a work is too clichéd.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/img/yueguang-baohe/202408291236394.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Of course, not everyone will find it clichéd. Everyone has their own range of cliché they can bear. At least to me, &lt;em&gt;White Snake&lt;/em&gt; feels somewhat narrow and extreme.&lt;/p&gt;
&lt;p&gt;This approach also often falls into a trap. The later films in the &lt;em&gt;White Snake&lt;/em&gt; series cannot break out of the frame they set for themselves. At that point, romantic attachment truly becomes a limitation.&lt;/p&gt;
&lt;p&gt;Oh—I seem to have reached the answer by accident. I did not know it from the beginning; I was only trying to discuss it, and arrived at my own answer that way.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Conclusion:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Probably no one can avoid being ordinary. I certainly cannot.&lt;/li&gt;
&lt;li&gt;Everyone has their own range of cliché they can bear.&lt;/li&gt;
&lt;li&gt;When romantic love is written too forcefully and treated as the only important thing, it easily becomes narrow and extreme, and easily falls into cliché.&lt;/li&gt;
&lt;li&gt;In &lt;em&gt;Pandora&apos;s Box&lt;/em&gt;, romantic love is more like bait that catches someone like me and makes me watch to the end. It is not the most important thing, and the film does not need it absolutely. I cannot say what is most important, though perhaps Uncle Tat&apos;s performance contains the answer.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;In terms of intention, are small domestic concerns inferior to feelings for the nation?&lt;/h2&gt;
&lt;h3&gt;The greater whole is only the composite unity and coordination of smaller homes.&lt;/h3&gt;
&lt;p&gt;My personal view is that the two are not opposed.&lt;/p&gt;
&lt;p&gt;Anyone who finished &lt;em&gt;Gu Jian 3&lt;/em&gt; may recognize this instantly.&lt;/p&gt;
&lt;p&gt;Although &lt;em&gt;Gu Jian 3&lt;/em&gt; reverses the focus on romance in &lt;em&gt;Gu Jian 1&lt;/em&gt; and &lt;em&gt;2&lt;/em&gt;, in the end it expresses a feeling of generations succeeding one another, sparks being passed on. Many people say it has been elevated.&lt;/p&gt;
&lt;p&gt;But the contribution of the smaller home within that greater whole cannot be erased.&lt;/p&gt;
&lt;p&gt;I spent the whole game, in my ordinary way, chasing after Yun Wuyue&apos;s beauty.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/img/yueguang-baohe/202408291251032.jpeg&quot; alt=&quot;Yun Wuyue&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Who understands how much Yun&apos;s heroic face hit me at first sight?&lt;/p&gt;
&lt;p&gt;And every line of “I see that your waist strength [demonic power] is weak.”&lt;/p&gt;
&lt;p&gt;The everyday life of Yun and Beiluo, and the romance they may have, were among my main reasons for continuing the game.&lt;/p&gt;
&lt;p&gt;At the end, Beiluo and Yun Wuyue embody the smaller home; Cen Ying embodies the greater whole. [There is no melodramatic plot here, no unclear third-party relationship. Little Ying is very cute, so do not imagine things carelessly.]&lt;/p&gt;
&lt;p&gt;If the game had made even the slightest ambiguity between Little Ying and Beiluo, it would absolutely have become the cliché I mentioned above. But it handles the plot well and holds the distance well.&lt;/p&gt;
&lt;p&gt;What I noticed more, however, was a question of lifespan. Cen Ying is human, while Beiluo is a demon and Yun a nightmare clan member; both are long-lived species.&lt;/p&gt;
&lt;p&gt;Their brief but brilliant intersection became the most astonishing point to me. How will Little Ying view that previous adventure through her long life to come?&lt;/p&gt;
&lt;p&gt;Much of the time, cliché is only a matter of forcing something too hard—whether it is the small home or the greater one.&lt;/p&gt;
&lt;p&gt;The former is narrowness and limitation; the latter is empty grandiosity. Many people dislike main-melody films because they usually cannot express the lofty intention they imagine, yet forcefully raise a banner. Is that not another kind of cliché, one that is even more uncomfortable?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Another conclusion:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The small home and the greater whole are not naturally opposed; they can coexist.&lt;/li&gt;
&lt;li&gt;Both the greater whole and the smaller one can fall into cliché.&lt;/li&gt;
&lt;li&gt;Each has its own audience. I respond more to the smaller home, perhaps because I have seen almost none of the greater whole expressed well.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;The Answer to the Third Question&lt;/h2&gt;
&lt;p&gt;At this point, the answer to the third point above can also be reached:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;“Scope” is only a high hat. When we call a work broad or narrow in scope, we are usually implying whether its director is narrow.&lt;/li&gt;
&lt;li&gt;Narrowness generally shares a feature: when one thing is valued too heavily and forced too hard, it becomes easy to grow narrow.&lt;/li&gt;
&lt;li&gt;A narrow work may itself communicate a somewhat extreme intention, which can make viewers uncomfortable when their views differ. Such works are usually unacceptable to me.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Finally, some screenshots from an LSP:&lt;/h2&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/img/yueguang-baohe/202408291306766.jpeg&quot; alt=&quot;LSP screenshot 1&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/img/yueguang-baohe/202408291307357.jpeg&quot; alt=&quot;LSP screenshot 2&quot; /&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Does this not have the feeling of Li Xiaoyao holding Zhao Linger?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/img/yueguang-baohe/202408291308270.jpeg&quot; alt=&quot;LSP screenshot 3&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/img/yueguang-baohe/202408291309066.jpeg&quot; alt=&quot;LSP screenshot 4&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/img/yueguang-baohe/202408291309460.jpeg&quot; alt=&quot;LSP screenshot 5&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/img/yueguang-baohe/202408291311747.jpeg&quot; alt=&quot;LSP screenshot 6&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/img/yueguang-baohe/202408291312843.jpeg&quot; alt=&quot;LSP screenshot 7&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/img/yueguang-baohe/202408291313300.jpeg&quot; alt=&quot;LSP screenshot 8&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/img/yueguang-baohe/202408291313638.jpeg&quot; alt=&quot;LSP screenshot 9&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/img/yueguang-baohe/202408291313909.jpeg&quot; alt=&quot;LSP screenshot 10&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/img/yueguang-baohe/202408291314052.jpeg&quot; alt=&quot;LSP screenshot 11&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/img/yueguang-baohe/202408291314550.jpeg&quot; alt=&quot;LSP screenshot 12&quot; /&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I could not resist posting this one more time. Other people may find it hard to understand and think both look ordinary, but the one at the far right somehow strikes my aesthetic exactly.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/img/yueguang-baohe/202408291316324.jpeg&quot; alt=&quot;LSP screenshot 13&quot; /&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Zixia should originally have gone in [[After A Chinese Odyssey Part Two: Cinderella]], but I had already captured so many shots for the ending. It was love at first sight; the LSP verdict is confirmed.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/img/yueguang-baohe/202408291326129.jpeg&quot; alt=&quot;LSP screenshot 14&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/img/yueguang-baohe/202408291310372.jpeg&quot; alt=&quot;LSP screenshot 15&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/img/yueguang-baohe/202408291311385.jpeg&quot; alt=&quot;LSP screenshot 16&quot; /&gt;&lt;/p&gt;
</content:encoded></item><item><title>After Under Current: The Jianghu Brotherhood of the 1980s and 1990s</title><link>https://xnnehang.top/en/posts/nilin/</link><guid isPermaLink="true">https://xnnehang.top/en/posts/nilin/</guid><description>Thoughts on Under Current and the brotherhood of the 1980s and 1990s jianghu.</description><pubDate>Tue, 20 Aug 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;After &lt;em&gt;Under Current&lt;/em&gt;: The Jianghu Brotherhood of the 1980s and 1990s&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;My dad took my brother and me to the cinema. The people in front of us, behind us, and to our right probably had never seen a combination as strange as ours.&lt;/p&gt;
&lt;p&gt;The usual groups are elderly couples, young couples, best friends, or brothers.&lt;/p&gt;
&lt;p&gt;It did make me miss those summer nights when my dad and I watched American television dramas: &lt;em&gt;The Lord of the Rings&lt;/em&gt;, &lt;em&gt;The Avengers&lt;/em&gt;, &lt;em&gt;Fast &amp;amp; Furious&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Films can be a bond; games can too. If I keep going, I will end up talking about &lt;em&gt;Black Myth: Wukong&lt;/em&gt; again. Recently I cannot stop myself from circling back to it, because there is so much I want to complain about and so much that still leaves me unsettled.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Zun Fei is a well-written character, especially in the scenes where he divides the money. His younger brothers respect him greatly too.&lt;/p&gt;
&lt;p&gt;His presence holds the screen without feeling affected, which is rare. I have not seen many mainland actors who can carry that kind of scruffy, gangster-boss charisma.&lt;/p&gt;
&lt;p&gt;The story itself is quite simple, but its central conflict works well.&lt;/p&gt;
&lt;p&gt;The director is considerate enough to arrange an off-screen narrator, Xi Lai, as if this were an art film. Overall, it feels a little like someone recounting a biography.&lt;/p&gt;
&lt;p&gt;At the end, the director even thoughtfully states what the film wants to say, so the audience does not have to think too hard.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“Zun Fei had talent. If he had been born in this era—if Zun Fei had been born in this era—he would have gained what he wanted: a career, love. He would not have needed to make a deal with the devil.”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Tragedy stays in the memory, while comedy merely passes by.&lt;/p&gt;
&lt;p&gt;Zun Fei still has to die in the end, but the imagined empty shot the director gives us softens the audience’s feelings a little. Then the film uses those words above to comfort us at the end, so that we do not get trapped in it.&lt;/p&gt;
&lt;p&gt;What stayed with me most was not really the romance, or the moral line about what one must not do.&lt;/p&gt;
&lt;p&gt;It was the bond between Zun Fei and his brothers: when he divides the money and a brother gets no share, he says, take mine. When they do receive it, he tells them to spend half themselves and send half home.&lt;/p&gt;
&lt;p&gt;That is a true big brother. He even teaches them how to live.&lt;/p&gt;
&lt;p&gt;When he goes down to the gambling boat, he still looks after every one of his brothers. It may be a little performative, but it brings out that feeling of &lt;em&gt;jianghu&lt;/em&gt; loyalty.&lt;/p&gt;
&lt;p&gt;That is also why Yao Wu risks his life to save Zun Fei.&lt;/p&gt;
&lt;p&gt;The casting for Yao Wu is excellent. At first glance, I knew he was the kind of friend who would stand by you. Though he gets lightly set up along the way, he understands this &lt;em&gt;jianghu&lt;/em&gt; loyalty even better than Zun Fei does.&lt;/p&gt;
&lt;p&gt;Zun Fei acts on it, but does not understand it. For Yao Wu, &lt;em&gt;jianghu&lt;/em&gt; loyalty is everything.&lt;/p&gt;
&lt;p&gt;This kind of loyalty is difficult to sum up. It was common in the old Hong Kong cop-and-robber and gangster films, so it suddenly brought back the Hong Kong films I used to watch. I grew up immersed in them.&lt;/p&gt;
&lt;p&gt;Also, Douban ratings cannot be trusted completely. At first I saw its score—six points—and thought it was definitely a bad film. But it was quite good overall. Especially when the characters spoke Cantonese, the feeling really came through.&lt;/p&gt;
&lt;p&gt;I like this film because it reminds me of the past. Saying that makes me sound even older.&lt;/p&gt;
</content:encoded></item><item><title>I Come Alone, I Leave Alone</title><link>https://xnnehang.top/en/posts/wo-yigerenlai/</link><guid isPermaLink="true">https://xnnehang.top/en/posts/wo-yigerenlai/</guid><description>On Frieren’s sense of time, and whether what passes is insignificant or precious.</description><pubDate>Sat, 17 Aug 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I have recently been watching &lt;a href=&quot;https://movie.douban.com/subject/36093351/&quot;&gt;&lt;em&gt;Frieren: Beyond Journey’s End&lt;/em&gt;&lt;/a&gt;. It touches on thoughts I had before when I watched fantasy stories and the &lt;em&gt;A Record of a Mortal’s Journey to Immortality&lt;/em&gt; animation. They are all very faint, perhaps because the more time passes, the more deeply my feelings hide.&lt;/p&gt;
&lt;h2&gt;Ten years is not even one percent of my life so far.&lt;/h2&gt;
&lt;p&gt;A little background: in the setting of Middle-earth, elves are almost like gods. Unless they die unnaturally or suffer endless grief, they remain in the world forever. There is also a melodramatic saying that an elf who falls in love with an ordinary human becomes ordinary too.&lt;/p&gt;
&lt;p&gt;Frieren is one of the few surviving elves. So she does not grow old and has no sense of time. I actually envy that: sleeping in late, taking afternoon naps, and sleeping until noon without a care. I know deeply how it feels to keep sleeping when I am sleepy. I can never have too much sleep.&lt;/p&gt;
&lt;p&gt;Having nothing to do, staying in a forest for thousands of years: elves are peaceful by nature and follow the way of nature.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/img/wo-yigerenlai/202408162251427.webp&quot; alt=&quot;Frieren&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Once death no longer exists, most anxiety would disappear too. But I cannot know what the anxiety of immortality feels like.&lt;/p&gt;
&lt;p&gt;When Frieren was over a thousand years old (fifty years before the Era of King Aureole), she and the Hero’s party defeated the Demon King after a journey of ten years.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/img/wo-yigerenlai/202408162304054.webp&quot; alt=&quot;The Hero’s party&quot; /&gt;&lt;/p&gt;
&lt;p&gt;There were two humans—a hero and a priest—a dwarven warrior, and Frieren, an elven mage.&lt;/p&gt;
&lt;p&gt;Their lifespans are roughly: hero [blue-haired] &amp;lt; priest [wearing glasses] &amp;lt; dwarf &amp;lt; elf.&lt;/p&gt;
&lt;p&gt;An ordinary human’s lifespan &amp;lt; a priest’s few extra decades &amp;lt; several centuries &amp;lt; ???&lt;/p&gt;
&lt;p&gt;At the end of their journey, their celebration happened to coincide with a great meteor shower that comes once every fifty years. Frieren said she would keep collecting magic and take them next time to a better place to see it, then simply left.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/img/wo-yigerenlai/202408162318900.webp&quot; alt=&quot;Meteor shower&quot; /&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“I will come back to see you all once in a while.”&lt;/p&gt;
&lt;p&gt;“…” Every companion knew Frieren had a poor memory, but just as expected, none of them saw her even once in the following fifty years.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;After wandering for a while, she returned to find that the hero had become an old man. After watching the meteor shower, he closed his eyes and passed away. Looking back, it hurts a little. It feels as though he held on just to see Frieren one last time.&lt;/p&gt;
&lt;p&gt;“Hero and Frieren” were a pairing too, an impressionistic kind of pairing. On the day of the hero’s funeral—the first year of the Era of King Aureole—Frieren finally realized, belatedly, that she had never truly tried to understand him. And that it seemed already too late. Her delayed reactions are truly long, and that is exactly why she is so adorable.&lt;/p&gt;
&lt;p&gt;From then on, all she could see were statues of the hero, and her pairing would forever exist only in memories.&lt;/p&gt;
&lt;p&gt;They were both so young in those scenes. They had spent only ten years together. For Frieren, that was only an instant.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“Why not take on an apprentice? At least you would have someone to keep you company on the road,” the dwarf once asked Frieren.&lt;/p&gt;
&lt;p&gt;“An apprentice? Even if I pass on everything I know, they will die soon enough anyway,” Frieren said.&lt;/p&gt;
&lt;p&gt;“That is not how relationships work…” the dwarf replied.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;In the eleventh year of the Era of King Aureole—perhaps; I cannot remember exactly—Frieren was set up by the priest Heiter to take Fern as her apprentice.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/img/wo-yigerenlai/202408162316077.webp&quot; alt=&quot;Young Fern&quot; /&gt;&lt;/p&gt;
&lt;p&gt;I call her Chubby Fern because she was really round as a child.&lt;/p&gt;
&lt;p&gt;Fern grew up quickly beside Frieren. Seven years passed in a flash; when she was small, Frieren could treat her as a daughter, and when she grew up, Fern could be the mother.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/img/wo-yigerenlai/202408162320493.webp&quot; alt=&quot;Fern grown up&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Fern also made Frieren understand that humans feel time very differently from her. Whenever Frieren tries to spend half a year or several years looking for something, she unconsciously watches Mama Fern’s expression.&lt;/p&gt;
&lt;p&gt;Time slowed down for Fern. In Frieren’s world, people were no longer wearing open-crotch pants one moment and leaning on canes the next.&lt;/p&gt;
&lt;p&gt;But even slowed down, time still moves. Fern is human after all. Frieren has already had her share of white-haired people carrying coffins—well, she really does have white hair.&lt;/p&gt;
&lt;p&gt;Yet there is no avoiding it: Fern will grow old, and Frieren will watch her grow old. Fern will die, and Frieren will probably watch her die too. From the time Frieren realized at the hero’s funeral that she should understand people better—when she decided to try to understand them—she also had to grieve for the deaths of the people she came to understand.&lt;/p&gt;
&lt;p&gt;Though ten years were less than one percent of her life, those ten years changed her. Or rather, the hero changed her.&lt;/p&gt;
&lt;p&gt;So what happens when Fern also leaves, when Frieren is alone again? Does she return to nature? But after receiving the warmth of Mama Fern’s companionship, the natural harmony she once had will only feel lonely and cold. Separation is unavoidable, and she must be alone again, carrying everything by herself, just as she walks on carrying the hero and Fern with her. Does this elderly elf’s delayed reaction only arrive after she loses someone?&lt;/p&gt;
&lt;p&gt;In the end, she still has to be alone.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/img/wo-yigerenlai/202408162241125.webp&quot; alt=&quot;Frieren alone&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;Is what passes insignificant or precious?&lt;/h2&gt;
&lt;p&gt;This is the dividing line of pessimism. Do you believe memory is nothingness, or that it has weight?&lt;/p&gt;
&lt;p&gt;Schopenhauer’s view was perhaps: “What has passed is as insignificant as if it had never existed.”&lt;/p&gt;
&lt;p&gt;Yet I still think that moments like these should be cherished more. I am not yet sure whether one person should carry the past forever. But I think, borrowing a line from &lt;em&gt;Nichijou&lt;/em&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Every ordinary day we spend may be a miracle happening continuously.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Moments—ordinary days—like these deserve to be cherished. Though for me, as a human, time still keeps moving forward.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/img/wo-yigerenlai/202408162342346.webp&quot; alt=&quot;Frieren and the hero, memory one&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/img/wo-yigerenlai/202408162343401.webp&quot; alt=&quot;Frieren and the hero, memory two&quot; /&gt;&lt;/p&gt;
&lt;p&gt;I have always felt it is easier to find myself in solitude. But if relationships like this exist, perhaps it is easier to find the real thing.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;I want the real thing.&lt;/em&gt;&lt;/p&gt;
</content:encoded></item><item><title>After The God of Cookery</title><link>https://xnnehang.top/en/posts/shishen/</link><guid isPermaLink="true">https://xnnehang.top/en/posts/shishen/</guid><description>Thoughts on The God of Cookery: a bowl of rice that marks a change, and breaking past appearances.</description><pubDate>Tue, 13 Aug 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;They changed the poster.&lt;/p&gt;
&lt;p&gt;It is a culmination of many things. Only an hour and a half long, yet I watched it with complete focus (for many other films, I drift away for half of the runtime).&lt;/p&gt;
&lt;p&gt;There is a little philosophy in it, though the director never explores it too deeply—only touches on it. Here are two moments, both points where Stephen changes.&lt;/p&gt;
&lt;h2&gt;A Bowl of Rice That Marks a Change&lt;/h2&gt;
&lt;p&gt;The first is how Stephen initially fusses over the 1982 and 1983 red wines, then takes out his frustration on someone after they bring him the wrong one.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/img/shishen/202408132301028.jpeg&quot; alt=&quot;The wine dispute&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/img/shishen/202408132301249.jpeg&quot; alt=&quot;The wine dispute, continued&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Later, in Temple Street, he eats a bowl of barbecue pork rice that Turkey makes and says, “This bowl of rice is so good” (&lt;em&gt;houhousi&lt;/em&gt;—it carries a little more feeling in Cantonese).&lt;/p&gt;
&lt;p&gt;Someone who is deeply sad may not cry, but when comfort reaches the sorest place, they may keep shedding tears.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/img/shishen/202408132302490.jpeg&quot; alt=&quot;Barbecue pork rice&quot; /&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I went back to take a screenshot and found one tear, only one. Details.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;People say crying scenes are hard to act. In truth, sadness is what is hard to act.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/img/shishen/202408132304819.jpeg&quot; alt=&quot;A single tear&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;Getting to Know Someone Again Begins by Breaking Past Their Appearance&lt;/h2&gt;
&lt;p&gt;The second is the problem of valuing looks. When Turkey first kisses Stephen, he frantically wipes his mouth in front of a mirror. Even after learning from people on the street that she had liked him for a long time, he still could not accept it. At first, I was psychologically following him too. I wavered a little, but not enough to shake the foundation of my own attachment to looks.&lt;/p&gt;
&lt;p&gt;Only when the thing itself was torn open and shown to me did I finally, in an instant, escape that pit of appearances. A wave of regret came over me, and I remembered her earlier bowl of rice and the time she shielded a knife with her hand. Only then did I truly recognize what was in my heart. Being overly concerned with looks is an illness. Being born to prefer cute things is not wrong; cute things make people feel close to them and fond of them. But if we stop at a first impression, perhaps we can never say that we have truly come to know someone further. The director tears this truth open for us through Turkey’s “death.” It is masterful, with no unnecessary explanation: a slip of paper, a song, and finally a bowl of rice. Nothing is simply handed over at once; it advances layer by layer.&lt;/p&gt;
&lt;p&gt;I can accept mediocrity. I can accept flaws. But I still have my limits, and this is one I cannot bear.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/img/shishen/202408132305946.jpeg&quot; alt=&quot;Karen Mok&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Thank you to this film, and thank you to the director.&lt;/p&gt;
&lt;p&gt;I like this kind of absurd and exaggerated yet real thing: comedy, tragedy, and then comedy again.&lt;/p&gt;
&lt;h2&gt;A Slip of Paper&lt;/h2&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/img/shishen/202408132307842.jpeg&quot; alt=&quot;Slip of paper one&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/img/shishen/202408132307904.jpeg&quot; alt=&quot;Slip of paper two&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;A Bowl of Barbecue Pork&lt;/h2&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/img/shishen/202408132309995.jpeg&quot; alt=&quot;A bowl of barbecue pork&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;Stayed Up Late Again&lt;/h2&gt;
&lt;p&gt;It is 11:11 p.m. If I have to get up at 5:30, only six hours remain. I will have to alternate walking and running.&lt;/p&gt;
</content:encoded></item><item><title>After Gold or Shit</title><link>https://xnnehang.top/en/posts/zouzoutingting/</link><guid isPermaLink="true">https://xnnehang.top/en/posts/zouzoutingting/</guid><description>Thoughts on Gold or Shit, pursuing success, and improving oneself.</description><pubDate>Tue, 13 Aug 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;img src=&quot;../../assets/img/covers/zouzoutingting.jpg&quot; alt=&quot;Gold or Shit&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;“After watching so many films, you still came home to live off your parents.”&lt;/h2&gt;
&lt;p&gt;The line that cuts deepest.&lt;/p&gt;
&lt;p&gt;I have thought about becoming a writer too. I was still thinking about it through high school.&lt;/p&gt;
&lt;p&gt;But if I once had the excuse that youth meant many possibilities, then when age no longer becomes an advantage, did I start to settle down?&lt;/p&gt;
&lt;p&gt;Yes, a little. At the same time, I am surprised that most of my past fantasies remained only fantasies, while very few ever became action.&lt;/p&gt;
&lt;p&gt;And once time has passed, can I simply say that the age for fantasies is over? When I search online, I find that many major web-novel authors began submitting work in middle school. I am startled by the gap between their ability to act and mine. I also wonder whether my own fantasies were only a waste of time.&lt;/p&gt;
&lt;p&gt;But thinking this way leads somewhere crooked again.&lt;/p&gt;
&lt;h2&gt;“That film was more than just a film to me.”&lt;/h2&gt;
&lt;p&gt;If the film they made were released publicly, most people in China would probably not even give it a passing score. In other words, the chance of it sinking without a trace would be high.&lt;/p&gt;
&lt;p&gt;But that raises a question: should public evaluation be the standard by which a film is judged? Put that way, it becomes clear. Although most poorly rated films are not worth watching, many highly rated films seem completely terrible to me too. Public evaluation is only one point of reference.&lt;/p&gt;
&lt;p&gt;Evaluation—or feeling—is always subjective.&lt;/p&gt;
&lt;p&gt;For Old Hu, that film means something extraordinary. For those who resonate with it, an art film that ordinary people find unbearably dull can be the most complete expression possible.&lt;/p&gt;
&lt;h2&gt;What I Have Been Pursuing Is Wrong&lt;/h2&gt;
&lt;p&gt;I hope to work remotely, from home. Or perhaps not work at all. That was the original intention.&lt;/p&gt;
&lt;p&gt;But gradually it has drifted away from that.&lt;/p&gt;
&lt;p&gt;Because I need not to go to work → I need exceptional ability → I need to achieve something in a field → I need other people to see me as successful → other people’s evaluation matters more than my own.&lt;/p&gt;
&lt;p&gt;This is a distorted transformation, infected by reality. It makes my original intention drift away. What was meant as self-improvement becomes the pursuit of others’ recognition. And this misplaced pursuit may in turn diminish me.&lt;/p&gt;
&lt;h2&gt;Success Leaves No Trace; Self-Improvement Does&lt;/h2&gt;
&lt;p&gt;No one’s success can be reproduced. Not in writing, filmmaking, game development, investing… anything.&lt;/p&gt;
&lt;p&gt;Yet successful people often exaggerate the twists and turns of their experience, shaping an image of themselves as resilient. They also give everyone a mistaken idea: that success is the result of hard work.&lt;/p&gt;
&lt;p&gt;The result of that mistaken idea is that countless people who work hard eventually—or even before the end—begin to feel lost. Especially when confronted with the group that survived the survivor bias, they feel particularly defeated and cannot see what they already possess. Looking forward, universal success leaves no trace to follow.&lt;/p&gt;
&lt;p&gt;As I said before, the goal is wrong. First of all, success is defined by the public. It is only a point of reference.&lt;/p&gt;
&lt;p&gt;A sophism:&lt;/p&gt;
&lt;p&gt;An old beggar has lived on the street for more than twenty years. Everyone on the street knows him. He accepts whatever people give him, along with their scorn, without resistance.&lt;/p&gt;
&lt;p&gt;A wealthy merchant is the richest person on that street. But you learn that Death will come for him at noon two months from now: he has tuberculosis.&lt;/p&gt;
&lt;p&gt;If you had to choose, which would you choose: the beggar or the merchant? Would you live another ten or twenty years without dignity, or spend your final two months extravagantly before dying?&lt;/p&gt;
&lt;p&gt;The ordinary standards by which meaning is measured are usually beyond one’s control. Pursuing success in the ordinary sense is no different from gambling. Gambling itself could be a subject on its own.&lt;/p&gt;
&lt;p&gt;The lessons you draw from a failed pursuit do not necessarily point toward success; nor does a successful person’s self-praise necessarily point toward success. No road is marked as leading to it. The more you treat it as the goal, the farther you may drift from it.&lt;/p&gt;
&lt;p&gt;To me, self-improvement seems more meaningful.&lt;/p&gt;
&lt;p&gt;But self-improvement faces another question: if death is inevitable, where do its meaning and value lie?&lt;/p&gt;
&lt;p&gt;Interesting, interesting. I have not found an answer yet.&lt;/p&gt;
</content:encoded></item><item><title>Pandora&apos;s Box</title><link>https://xnnehang.top/en/posts/panduola/</link><guid isPermaLink="true">https://xnnehang.top/en/posts/panduola/</guid><description>On coughing up blood, awareness of death, and personality change.</description><pubDate>Sun, 04 Aug 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;img src=&quot;../../assets/img/covers/panduola.jpg&quot; alt=&quot;Pandora&apos;s Box&quot; /&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I coughed up blood last night. I coughed up blood the night before too.&lt;/p&gt;
&lt;p&gt;There was no reason for it, and it was not that life suddenly seemed precious. It was only that the strained disguise I had kept up until yesterday had fallen away.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Here, coughing up blood means tuberculosis, which was probably incurable at the time. Now, though, tuberculosis can be cured in the vast majority of cases.&lt;/p&gt;
&lt;p&gt;Still, I am curious about how the book’s remarkable health retreat managed to cure so many people through natural therapy.&lt;/p&gt;
&lt;p&gt;But that is only an aside. &lt;strong&gt;A sudden, life-threatening illness can tear away the veil that covers one’s awareness of life, while also making death feel less frightening.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;A renewed awareness of life can probably bring about a major change in personality. Psychology has no shortage of such cases. In the book, after entering the sanatorium, the protagonist changes from taciturn to talkative. He also says that he seems to have become a new man.&lt;/p&gt;
</content:encoded></item><item><title>After The Poppy</title><link>https://xnnehang.top/en/posts/yumei-cao/</link><guid isPermaLink="true">https://xnnehang.top/en/posts/yumei-cao/</guid><description>Reading notes on Natsume Sōseki&apos;s The Poppy: attention, drama, and the frankness of human nature.</description><pubDate>Wed, 17 Jul 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;img src=&quot;../../assets/img/yume-caohou/202407172303464.jpeg&quot; alt=&quot;The Poppy&quot; /&gt;&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;Attention is sparse.&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;I read the first half in a physical book, translated by Lu Qiushi; the second half on an e-reader, translated by Moro Miya (a name so hard to remember that I forgot it after seeing it once).&lt;/p&gt;
&lt;p&gt;I have to say that I am becoming less and less receptive to paper as a medium. I have grown used to reading on an e-reader. Perhaps the type in print is too small: I took in almost only the first sentence of each paragraph, and across the first half of the book there were only four or five places where I could focus. In the second half, though, my attention became much more concentrated. The translator may have had something to do with it, and the density of the plot cannot be ignored either.&lt;/p&gt;
&lt;p&gt;The first half is comparatively fragmented, and it does not deliberately lay out the characters’ relationships as a play would. Untangling the relationships among Fujio, Iris, Kōno, Ono, and Munetika is difficult.&lt;/p&gt;
&lt;p&gt;I also complained halfway through that the dialogue ought to have labels such as A. or MJ before it. Whenever a conversation begins, it goes on for a long time—especially the opening conversation between Munetika and Kōno—with no names inserted at all. With my scattered attention in the first half, I could not even tell who was speaking. I did not figure out who wore the fox-fur vest until nearly the end.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;This is unquestionably a play.&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;I do not know much about drama, and I have seen very little of it: &lt;em&gt;The Merchant of Venice&lt;/em&gt; and several works written by Mishima. Borrowing Watanabe’s remarks about ancient Greek drama in &lt;em&gt;Norwegian Wood&lt;/em&gt;, this work is like Euripides: at the end of the plot, a character appears and resolves every problem that had seemed unsolvable. In this novel, Munetika is that character. Yet it is also reasonable. The cause of every problem is only Ono’s hesitation and concern for appearances, while Munetika is thoroughly frank and quite carefree. One act of honesty could solve everything, but from Ono’s perspective, I felt that there was no way forward or back.&lt;/p&gt;
&lt;p&gt;Let me first give my overall impression of the work, then pick out the parts I especially care about.&lt;/p&gt;
&lt;p&gt;The translator’s preface mentions that this was Natsume’s first work after he left teaching to become a full-time novelist. It can absolutely be called a love story, and as the number of installments increased, so did the pressure on him. This work apparently does not hold an especially strong position among all his works; on the contrary, scholars even consider it quite poor.&lt;/p&gt;
&lt;p&gt;Coincidentally, one of the few plays I have seen is &lt;em&gt;The Merchant of Venice&lt;/em&gt;, and these two works feel extremely similar to me. More coincidentally, the novel I read just before this was &lt;em&gt;Kokoro&lt;/em&gt;. Earlier still, I read &lt;em&gt;I Am a Cat&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;From these three works by Natsume, I can infer that his audience is extremely broad—almost all East Asians—and that his work is almost entirely free from the constraints of its era. Many Chinese realist writers are difficult and boring to read without historical context. That may be why I do not read much Chinese literature: it is too heavy. &lt;em&gt;Fortress Besieged&lt;/em&gt; is an example of something not bound by its era. (Some may think it petty, but I like this kind of thing.) I do not like people who, whenever they speak of a work’s intent, immediately raise it to the nation and the world. Though “the spark passes on, flying on without cease” from &lt;em&gt;GuJian 3&lt;/em&gt; moves me, I think and reflect more often on myself. (Perhaps I was only lamenting that my one life is too short beside a thousand autumns and ten thousand generations.) “Petty” and “grand” are only different points of focus. I prefer to observe the individual human self regardless of time or place, so I am “petty,” and even a little resistant to “grand narratives.” Some of my own problems may be no different from those of people a hundred years ago. In that sense, there is no need to talk about an era. A person alone already has far too many problems. So perhaps a work does not always have to reflect the problems of its time.&lt;/p&gt;
&lt;p&gt;All three of Natsume’s works reflect certain unnoticed defects in people who are twisted and self-contradictory, along with possible solutions.&lt;/p&gt;
&lt;p&gt;In &lt;em&gt;The Poppy&lt;/em&gt;, Munetika offers the solution. In &lt;em&gt;Kokoro&lt;/em&gt;, Sensei chooses to bury the problem forever. But readers will also analyze it for themselves and follow the author’s hints to their own answers.&lt;/p&gt;
&lt;p&gt;It is interesting. If I considered &lt;em&gt;Kokoro&lt;/em&gt; and &lt;em&gt;The Poppy&lt;/em&gt; separately, I would only say I recommend them, four stars. But I read both recently and they have a considerable connection when placed together, so I would say I strongly recommend them, five stars.&lt;/p&gt;
&lt;p&gt;More coincidentally, I had no idea what was going on in the first half of both books, and only concentrated in the second half. Perhaps they assembled themselves together in my mind in some strange way.&lt;/p&gt;
&lt;h4&gt;&lt;strong&gt;Many authors keep tirelessly and unconsciously drawing stories with the same core. I know several directors like this too (Hirokazu Kore-eda). It feels like a fixation.&lt;/strong&gt;&lt;/h4&gt;
&lt;p&gt;In &lt;em&gt;The Paris Review&lt;/em&gt;, the interviewer’s summary of Murakami’s works was roughly this: a man loses a woman—or something—and, after losing her, he always begins to search, so he changes and may move back and forth between two worlds. Usually another woman helps him during that search. Compared with the woman who was lost, this woman is livelier, more passionate, and less restrained. The woman being sought, by contrast, may be cold, distant, and quiet.&lt;/p&gt;
&lt;p&gt;Murakami accepted this summary too. When authors repeat such portrayals as they produce one work after another, readers often assume that they have run out of ideas. Yet Natsume describes roughly the same problem in &lt;em&gt;Kokoro&lt;/em&gt; and &lt;em&gt;The Poppy&lt;/em&gt;. The two descriptions make it clearer, and both also try to solve it.&lt;/p&gt;
&lt;p&gt;People can never grasp the full shape of the problem that troubles them most deeply, or they worry that it cannot be solved at all. Natsume’s writing—and that of most authors who repeatedly narrate similar things—is not repetition but exploration. If several works connected by a theme can be read together, perhaps they can help with the predicament of the problem itself. Of course, as a novel, its storytelling cannot be ignored, and &lt;em&gt;The Poppy&lt;/em&gt; has no flaw besides its fragmentation.&lt;/p&gt;
&lt;p&gt;I understand a little better why Mishima wrote so many plays. Drama is the clearest and most concise form of fiction, almost the simplest expression of the great way. It reflects problems with violent directness, without adding the author’s views. Tragedy has its own charm too; a passage near the end of Kōno’s text can serve as a reference. Perhaps I have reached the age when I can read Shakespeare.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;The Part I Especially Care About: Perhaps I Should Marry Into Someone Else’s Family&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;Leaving aside the central conflict I vaguely discussed earlier, between the frankness human nature needs and the concern for appearances needed to live in society,&lt;/p&gt;
&lt;p&gt;I have to say that Fujio is a woman who surprises me. Whether Iris or Sayoko, they are only characters in a play; their behavior and personalities can be placed within ordinary reason and categories. I can simply say that Iris is a rough woman who toys with others’ feelings, while Sayoko is innocent and fragile. But I cannot simply summarize Fujio or make a judgment about her. Yet she is so simple and pure. This touches on something she and Kōno discuss: “It is better not to marry, and to remain unchanged,” and “You can stay carefree like this.”&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;She has spiritual insight. (In Buddhism, this seems to mean the capacity for sudden enlightenment. It includes intelligence, but more than that, innocence.)&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I especially care about her conversation with Kōno: “When you move, you change,” “Leaving your parents and brother will change you,” “You will become clever,” and “It is better not to marry; it is good to stay unchanged forever.”&lt;/p&gt;
&lt;p&gt;“I do not want to get married.”&lt;/p&gt;
&lt;p&gt;At the time, I really felt Fujio’s innocence in that conversation. And I must say, Kōno was not called a philosopher for nothing: he is a true philosopher. Philosophy ultimately cannot be confused with literature. Writers often dwell in anguish or sentiment, but Kōno’s attitude of not caring about circumstances is truly transcendent. Writers are still more concerned with reality and practicality than philosophers are.&lt;/p&gt;
&lt;p&gt;I think Fujio changed after that conversation, as if she reached enlightenment beneath a bodhi tree. She stepped out of the role the author had assigned her. She changed from “an innocent, romantic, carefree younger sister” into “a younger sister who decides to remain innocent and carefree.” She did not become cleverer; she became clearer and more aware. She moved from ignorance to deciding that it would be enough to remain unchanged forever.&lt;/p&gt;
&lt;p&gt;If beauty could be held still, that too would be something moving.&lt;/p&gt;
&lt;p&gt;So I still cannot explain in a single sentence what kind of person she is. But whatever the case, I like her this way.&lt;/p&gt;
&lt;p&gt;Also, I still think Kōno’s words are worth considering further. Perhaps remaining unchanged is a good thing. (Some may argue that no one remains unchanged, and in one sense that is certainly true. But some people become increasingly pure, such as eminent monks who let go of attachment to the self.)&lt;/p&gt;
&lt;p&gt;Maybe I should marry into someone else’s family someday, so that the other person can remain unchanged rather than changing by leaving home.&lt;/p&gt;
&lt;p&gt;Though my attention was scattered when I first read it, by the time I have written this, Natsume is no longer just an unfamiliar name to me. I can say that I chewed over the parts I wanted from &lt;em&gt;Kokoro&lt;/em&gt; and &lt;em&gt;The Poppy&lt;/em&gt; carefully, and savored them again.&lt;/p&gt;
&lt;p&gt;Human consciousness and attention are difficult to judge. We remember what we like, and what we see is easy to remember. It is precisely because of this strange mechanism that there are so many interesting works.&lt;/p&gt;
</content:encoded></item><item><title>After Young Babylon</title><link>https://xnnehang.top/en/posts/shaonian-babilun/</link><guid isPermaLink="true">https://xnnehang.top/en/posts/shaonian-babilun/</guid><description>Thoughts on Young Babylon, Bai Lan, interesting people, and being nineteen.</description><pubDate>Mon, 15 Jul 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;img src=&quot;../../assets/img/covers/shaonian-babilun.jpg&quot; alt=&quot;Young Babylon&quot; /&gt;&lt;/p&gt;
&lt;p&gt;When a real connection is not close enough, people seek compensation through the body, as if that can offer certainty.&lt;/p&gt;
&lt;p&gt;But I prefer Vivian. The physical part is only an addition.&lt;/p&gt;
&lt;p&gt;If going to Tibet is the dream journey of many young artistic people, then meeting you at twenty would be my fantastical journey.&lt;/p&gt;
&lt;p&gt;I like this: thinking that there are still people like Bai Lan in the world. There are too many beautiful people, but too few interesting ones. As long as they exist, it is a comfort, even if I never meet them. And most of the time, that kind of interestingness is out of step with its era. Simply put, it seems distinctive, ahead of its time, perhaps even shocking to people then.&lt;/p&gt;
&lt;p&gt;I finished it in eight and a half hours. I found all the stories the author wrote full of flavor, especially those involving Bai Lan. But at the end, he wrote a poem that seemed to come from nowhere and lead nowhere. I probably do not have the constitution for reading modern poetry; I skimmed right past it. I may be destined not to be a reader of poetry, but stories move me deeply. I am grateful to still have this one pleasure.&lt;/p&gt;
&lt;p&gt;I remember a famous writer whose daughter published poetry. It was not very good—or rather, it read like a running account—yet she still wanted to publish more. Her father was dissatisfied but never said so directly. Lu Xiaolu mentions talent many times. It is not her fault that she has no talent for writing poetry, and it is not her fault that she has no aesthetic sense for poetry either. But I cannot help remembering Lu Xun’s warning not to become merely a writer of empty words.&lt;/p&gt;
&lt;p&gt;This book writes about missed chances and remembrance, but most of it happens when Lu Xiaolu is nineteen or twenty. I am nineteen now. I attend an unremarkable university and study a major that leaves me confused. Yet I keep thinking that I am no longer young. It is rather embarrassing. I spend too much time thinking about these things.&lt;/p&gt;
&lt;p&gt;Will I ever meet a “Bai Lan”? Not someone with the same personality, though I really do like people who are distant. But could I meet a Jane Eyre? Someone I could speak with soul to soul.&lt;/p&gt;
&lt;p&gt;I have to say that the author’s roguish air is infectious. Even the way I speak has started to sound affected. But mine is only a fake roguishness; it cannot compare with the real thing.&lt;/p&gt;
</content:encoded></item><item><title>Love in Yushima</title><link>https://xnnehang.top/en/posts/tangdao-zhi-lian/</link><guid isPermaLink="true">https://xnnehang.top/en/posts/tangdao-zhi-lian/</guid><description>Reading thoughts on Love in Yushima: the innocence of geisha and a love that remains pure.</description><pubDate>Mon, 15 Jul 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;img src=&quot;../../assets/img/covers/tangdao-zhi-lian.jpg&quot; alt=&quot;Love in Yushima&quot; /&gt;&lt;/p&gt;
&lt;p&gt;When I first read &lt;em&gt;Snow Country&lt;/em&gt;, what drew me in most was probably Komako’s way of speaking. It had a kind of beautiful incoherence—though that may not be the right way to put it.&lt;/p&gt;
&lt;p&gt;She was completely unreserved about affairs between men and women, and teased people about them. And every so often she would say something that seemed to come from nowhere: “It’s so cold,” or “Like a fool.” She was as cute as a carp suddenly surfacing in a pond to blow a bubble.&lt;/p&gt;
&lt;p&gt;In &lt;em&gt;Snow Country&lt;/em&gt;, Shimamura describes Komako as clean and fair-skinned, as though she would blush from her face all the way down the back of her neck, like some adorable animal. In &lt;em&gt;Love in Yushima&lt;/em&gt;, Chōkichi refuses a soldier’s harassment and slaps him. When she is pursued and hides among an opera troupe to slip past them, she gives me the same feeling. Innocence and romance seem to be a geisha’s loveliest traits.&lt;/p&gt;
&lt;p&gt;Komako once told Shimamura to visit her every year; it would be enough just to meet once and stay for a while. Chōkichi also tells Kamitsuki that even if he cannot marry her, she does not want to trouble him. She can support him. She can be a geisha all her life, as long as he does not abandon her. Their devotion seems the same, though one is in Tokyo and the other in snow country—perhaps Hokkaido or Kyoto, but “snow country” always feels more fitting.&lt;/p&gt;
&lt;p&gt;There is something else: the love of Chōkichi and Komako transcends sex.&lt;/p&gt;
&lt;p&gt;When Chōkichi and Kamitsuki share a bed, the scholar Kamitsuki burns with desire. He says that he has retained only a thread of reason, as if a cold dragon protects his body.&lt;/p&gt;
&lt;p&gt;But Chōkichi is the opposite:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;One morning, Chōkichi suddenly woke up and shook the half-asleep Kamitsuki awake. Looking around in surprise, she told him about her dream. In it, she stood in the dark holding three bunches of unopened iris flowers. Then everything around her suddenly brightened, and sunlight shone in. Bathed in golden light, she watched the three bunches of iris flowers bloom together in an instant. “Why is that?” she asked Kamitsuki with innocent delight. Kamitsuki was trapped in a nightmare, tormented in an illusion and drenched in cold sweat. Hearing her dream, he felt ashamed and blushed. Beside that holy white lotus, unstained though it grew from mud, his own heart seemed filthy. Only then did the scholar deeply understand Chōkichi’s spotless heart.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;It could be said that reason and instinctual sexual desire do not simply trade places: having more of one does not mean having less of the other.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Love in Yushima&lt;/em&gt; gave me a chance to revisit an old dream. I once fell at Komako’s feet, and now I find again that perhaps what I love is simply girls like Chōkichi and Komako: innocent and clean. Yet they are also resilient. That is how Komako can play the clearest notes on her shamisen in winter, and how Chōkichi can survive being a bonded geisha without losing the integrity of her character.&lt;/p&gt;
&lt;p&gt;Perhaps they understand the noblest kind of love in this world.&lt;/p&gt;
</content:encoded></item><item><title>The Deadline</title><link>https://xnnehang.top/en/posts/zuihou-qixian/</link><guid isPermaLink="true">https://xnnehang.top/en/posts/zuihou-qixian/</guid><description>Reading notes on The Deadline: project management, design, and a sense of purpose.</description><pubDate>Wed, 10 Jul 2024 00:00:00 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;This was probably the first novel I borrowed from the library as a freshman. After switching to e-books, I never borrowed books again. I miss it a little.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;Let me start from the beginning of the notebook:&lt;/h2&gt;
&lt;p&gt;Not much to say: this notebook is for recording things related to reading, especially reflections afterward. I would also like to have neat reading notes like Xiaoyin’s. I tried many times before, but rarely finished them. Usually I would go off to do something else halfway through, leave them there, or use the notebook for something unrelated. Sigh.&lt;/p&gt;
&lt;p&gt;Reading often—or at least sometimes—lets me calm down between playing games and learning things (work). It activates a different part of my mind too. Rather than learning something, playing games, then learning something again, which only makes me stubborn, reading is a good relaxant. During that time, I can think about nothing at all, or think about impractical things unrelated to life.&lt;/p&gt;
&lt;h1&gt;&lt;em&gt;The Deadline&lt;/em&gt;, Tom DeMarco&lt;/h1&gt;
&lt;h2&gt;#An Unexpected Encounter&lt;/h2&gt;
&lt;p&gt;Finding it was an accident, and perhaps fate. I had been looking for another book with the same title by a different author. Only after requesting it from the library did I realize this was a happy mistake.&lt;/p&gt;
&lt;p&gt;At first, seeing that it was a project-management book and also a novel, I assumed it would be another industry person trying to show off their expertise while also trying to write something accessible—and failing to write a decent novel.&lt;/p&gt;
&lt;h2&gt;#What Drew Me In&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;But it caught my attention perfectly. There were three reasons.&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The cute and alluring Ms. Julian, who is also a kidnapper: a charming contrast.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I admit that my initial affection for this novel was built on liking its female character.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;It is about software engineering and programmers collaborating on a project. &lt;strong&gt;I am interested in that.&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I have to say that my thinking has become somewhat programmer-like now, and I need chances to step outside that way of thinking.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;I made it through the first twenty minutes.&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;At the beginning, perhaps because I had not read a novel in so long, I could not immerse myself. My mind and eyes would not connect, and I felt sleepy. But after twenty minutes, I got into the zone.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Many novels may reveal their lovely side as long as you make yourself open them and read for twenty minutes.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;That is when reading becomes enjoyable.&lt;/p&gt;
&lt;h2&gt;#Some Excerpts and Summaries&lt;/h2&gt;
&lt;p&gt;Here are some notes. Some are summaries; others are copied directly.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;How to handle the pressure that accumulates over time once a software project begins.&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Pressure is always lurking in the air, and it can catch people off guard once it takes shape.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;The day a project begins and the day it nears completion are actually equivalent&lt;/strong&gt;, yet we are relaxed at first and frantic later. At the beginning, our mindset is too indulgent.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The best way to solve pressure is to extinguish it before it takes shape: prevent illness before it appears, prepare early, finish early. But &lt;strong&gt;do not remain under pressure and tension all the time. Short-term pressure may seem to solve many things, but long-term pressure only kills thought.&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Keep a cynical attitude. Learn from cats; learn from the Monro programmers who are like cats. &lt;strong&gt;No matter how the outside world demands or pressures me, I first consider only completing the minimum.&lt;/strong&gt; Or keep your own judgment. Do not be like Webber, dizzy from the overwhelming requirements in the documents.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Finish only one goal at a time.&lt;/strong&gt; Do not try to debug two bugs at once.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Treasure the feeling of suddenly becoming light after a project ends&lt;/strong&gt;, and remember afterward to sort out what you gained and learned. A project ending does not mean you are finished.&lt;/p&gt;
&lt;p&gt;--- Let us hope we can stop Belloc from appearing in our lives. (The endless, chattering client.)&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;P.S.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Julian is so cute when she says, “He must miss me.”&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Every night, Webber sits at his desk and writes down experience and notes. This is only one way the author teaches us, but Webber tells a reporter: &lt;strong&gt;“I will never open this notebook again, but its 101 principles have been burned into my consciousness.”&lt;/strong&gt; That is really cool. I probably write my blog from the same feeling.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;So I cannot help considering why I started writing this notebook. It certainly was not so I could reread it over and over. After all, once I have written something down, what should be remembered has already been remembered.&lt;/p&gt;
&lt;p&gt;At the same time, I think reading and writing reflections in this way helps the continuity of my reading and thinking, and also helps me form a good reading habit.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;WTF. Ever since I started using an e-reader, I have not picked up a pen. I also wonder whether I have stopped using my brain at the same time.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;#Design: Code with Divine Assistance&lt;/h2&gt;
&lt;p&gt;&lt;em&gt;The Deadline&lt;/em&gt; really hits my interests: programming projects, time management, human resources, and a charming kidnapper.&lt;/p&gt;
&lt;p&gt;Here I will talk about the programming-design ideas mentioned in the project.&lt;/p&gt;
&lt;p&gt;Aristotle believes that &lt;strong&gt;designing a project’s modules before writing the program is important, important enough to deserve most of the time.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;What ordinary people usually understand by design here is:&lt;/p&gt;
&lt;p&gt;Function → structure → implementation. Working backward from the result toward the underlying details and breaking things down. Before writing a project, you should know clearly what each part will do, along with its function and implementation.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;But designing only the implementation of functions is not enough. It is not the endpoint.&lt;/strong&gt; The real design exists in the programmer’s mind: what code module needs to be implemented now, what its pseudocode should look like. The final programming is only like putting puzzle pieces in their proper places. This can almost eliminate debugging: implement and verify the function of one small code block at a time. But I often write whatever comes to mind. I get trapped by bugs caused by a particular implementation, and instead of trying a different implementation, I change many things just to debug until it runs normally. Those changes not only waste a great deal of time; they may also pull parts further away from the original design.&lt;/p&gt;
&lt;p&gt;I think what Aristotle really wants to emphasize is &lt;strong&gt;having another perspective while writing code. When we get stuck in a bug, we know to change approaches rather than stubbornly fight it. While implementing, it is as if there is a puzzle background guiding what this piece and the next one should be.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The design he emphasizes is probably that perspective and that puzzle background. If writing code is like receiving divine assistance, that perspective is the god.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I can say that my programming habits are very bad right now. I write whatever I think of. Maybe I should learn to write pseudocode in my mind, try to reason about the next step and the current one, then work out the whole picture.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;No program can be written without this sort of design. Still, most people get used to designing while they code. It is a little like chess: some people see more of the whole board, others only the local position; some can predict ten or more moves at once, while others can see only one or two moves before stopping.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I am typically limited and short-sighted. I once called my programming habits carefree, but when I encounter a larger project, &lt;strong&gt;every added feature can pull on the whole system, requiring repeated changes to all the code&lt;/strong&gt; rather than changes only to the local function. That makes me feel &lt;strong&gt;I need to change. Maybe I need standards, and I need to see further.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Design is consciously predicting the course of a chess game. But you do not need to see every possibility before you dare make a move; there would never be enough time. You only need to &lt;strong&gt;see one linear path that reaches the finish. How to optimize is something to consider after reaching it. Trying to optimize while writing a feature that has not even taken shape is a grave mistake. In the end, do you spend more time writing the feature or debugging and optimizing it?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Consciously &lt;strong&gt;predict a target code block that can reach the result&lt;/strong&gt;. If possible, predict two and keep one as a backup. When one route fails, switch to the other instead of immediately debugging. Many people impulsively start writing right away, but the mistakes this causes—and the time later spent repeatedly debugging and testing—far exceed the time spent predicting first. Besides, no one enjoys running a program again and again, repeatedly investigating the cause of an error. If it can be done in one go, why not?&lt;/p&gt;
&lt;p&gt;And doing it in one go does not mean writing everything and then running it once successfully. That is impossible; there will always be deviations and bugs. It means &lt;strong&gt;writing each predicted code block in one pass, running it, passing once, and achieving the expected function. Only after verifying that function do I move on to the next prediction-and-writing stage.&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;#What Stays with Me Most&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;When a project has just begun, the crisis exists and the goal is clear. Yet the sense of crisis is weak, almost pleasant, while the sense of purpose is entirely absent—almost aimless.&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;A sense of purpose is a positive and excited state of mind.&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;We often have goals but lack a sense of purpose because we recognize those goals only as “things we ought to do,” rather than “things we especially want to do and achieve.”&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;#An Aside&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;The story of that UI from two days ago: at first, my roommate was assigned to write the UI and I was assigned to write the functionality. We had a week, with a defense on Friday. On Thursday afternoon, he gave me code that ran but that I found deeply unsatisfying—&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;He said he wanted to learn how to write UI properly. At first he boasted that he would make it look good. But what he eventually gave me had no beautification at all: he drew a few boxes, made a few controls, put functions into them, and that was it.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The other issue was speed. Several parts of the software requirements involved taking photographs and facial recognition—in short, opening the camera. When he clicked a button, it initialized the camera. When another part needed the camera, it stopped the first one, released it, and initialized another. And to initialize the camera, he used:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;self.camera = cv2.VideoCapture(0)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This function took more than three seconds every time. In other words, I clicked to open the camera and waited four seconds; I clicked to start recognition and waited another five. A control took four or five seconds to respond, and it was single-threaded, so during the response the window could not receive messages or perform any other operation.&lt;/p&gt;
&lt;p&gt;I was practically coughing up blood. I told him, “You are going to leave it like this without optimizing anything?” He said a device has only one camera; initializing two at once would crash it, so he could only stop one and open the other. He even demonstrated the crash to me.&lt;/p&gt;
&lt;p&gt;It was already Thursday afternoon. I told him to optimize or beautify it a little more. He said, “Optimize my ass. It works. If you want it optimized, do it yourself,” then went back and opened League of Legends.&lt;/p&gt;
&lt;p&gt;I only felt that the gap between his beginning and end was enormous. He did not beautify it, and he did not optimize it.&lt;/p&gt;
&lt;p&gt;In the end, I really did take it on myself. This is where the distinction between goals and a sense of purpose, tasks and things one ought to do, becomes relevant.&lt;/p&gt;
&lt;p&gt;For him, there was a goal at first, and perhaps he was even overly excited. Later, though, it became only a task. He had no real sense of purpose and only completed the minimum.&lt;/p&gt;
&lt;p&gt;I was the opposite. I am obsessed with UI beautification—or rather, I am obsessed with anime. If I write something, it must have a bit of anime in it. So I added a background image, a logo, and icons. When I write these things, they are usually extras; I may not know exactly what to make, but the positive and excited mindset that comes with having a goal stays with me.&lt;/p&gt;
&lt;p&gt;For the speed optimization, I initialized the camera when the program started and used it globally afterward. In the end, startup still took four or five seconds, but every other control responded immediately.&lt;/p&gt;
&lt;p&gt;I call that state of having a sense of purpose &lt;strong&gt;writing my own thing&lt;/strong&gt;. When I try to write my own thing, it has nothing to do with other people’s requirements; it is simply what I want. Anime-style beautification is what I want, and that is the key that lets me enter that state. But doing this often makes me skip meals, which is bad for my health.&lt;/p&gt;
&lt;p&gt;And before trying to write my own thing, I usually make something terrible first—the minimum—at the fastest speed, then optimize it on that foundation. That leaves enough time to think about what can be done later and enough time to tinker. My roommate spent four days delivering what I considered the bare minimum, then stubbornly said that it worked. That made me really angry.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
</content:encoded></item><item><title>Love in the Buff</title><link>https://xnnehang.top/en/posts/chunjiao-yu-zhiming/</link><guid isPermaLink="true">https://xnnehang.top/en/posts/chunjiao-yu-zhiming/</guid><description>Reflections on Love in the Buff and the bonds that time creates</description><pubDate>Mon, 08 Jul 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;If love at first sight makes people self-conscious around each other, then Chun Jiao and Zhi Ming must be the least self-conscious couple imaginable.&lt;/p&gt;
&lt;p&gt;I had meant to watch &lt;em&gt;Love in a Puff&lt;/em&gt;, but I ended up watching &lt;em&gt;Love in the Buff&lt;/em&gt; first. I suppose that means I missed the first film; even if I go back to it now, the experience can no longer have the purity of a first viewing.&lt;/p&gt;
&lt;p&gt;Still, I did not really lose anything. I had only been looking for something to watch over dinner tonight, having not watched a film attentively in quite a while. This was a pretty good place to begin again.&lt;/p&gt;
&lt;h3&gt;The Beginning&lt;/h3&gt;
&lt;p&gt;Why did it feel slightly stitched together? The atmosphere between Chun Jiao and Zhi Ming—or rather, the feeling of the film&apos;s opening stretch—strongly resembled an arthouse film. The camerawork felt casual, and even the focus seemed casual. The early mention of Mandy, Chun Jiao&apos;s closest friend, and her history of supposedly bringing misfortune to her husbands felt like something out of an absurd comedy novel or film. Even when Chun Jiao and Zhi Ming were at odds, everything remained lighthearted. It reminded me of Stephen Chow and Cecilia Cheung in &lt;em&gt;King of Comedy&lt;/em&gt;.&lt;/p&gt;
&lt;h3&gt;The Camerawork&lt;/h3&gt;
&lt;p&gt;Once Xu Zheng appeared, the entire visual language seemed to change. It became weightier and more delicate, like the sudden difference between something casually filmed on a phone and something shot with a professional camera setup. Perhaps I was simply fixated on his enormous head, but wherever Xu Zheng appeared, the whole style seemed different. Maybe his presence was simply too strong. Then there was Ben, played by Huang Xiaoming. Although he kept saying that people merely told him he looked like Huang Xiaoming, I could not help feeling that he was unable to let the resemblance go. Something about it felt out of place.&lt;/p&gt;
&lt;p&gt;I found Miriam Yeung&apos;s scenes the most comfortable to watch. When I was young, I watched her and Richie Jen in &lt;em&gt;Elixir of Love&lt;/em&gt; many times. Later, I also watched &lt;em&gt;2 Become 1&lt;/em&gt;. I love scenes with Miriam Yeung in them; they give me the feeling of returning to the past. But why is she so drawn to playing women who cannot find anyone to marry, whether in &lt;em&gt;Elixir of Love&lt;/em&gt;, &lt;em&gt;2 Become 1&lt;/em&gt;, or &lt;em&gt;Love in the Buff&lt;/em&gt;?&lt;/p&gt;
&lt;p&gt;I love the humor and comic beats of films such as &lt;em&gt;Flirting Scholar&lt;/em&gt;, &lt;em&gt;King of Beggars&lt;/em&gt;, &lt;em&gt;A Chinese Odyssey Part One: Pandora&apos;s Box&lt;/em&gt;, &lt;em&gt;Fight Back to School&lt;/em&gt;, and &lt;em&gt;Elixir of Love&lt;/em&gt;. They probably shaped a large part of my personality.&lt;/p&gt;
&lt;h3&gt;Finishing Move&lt;/h3&gt;
&lt;p&gt;But the film at hand is &lt;em&gt;Love in the Buff&lt;/em&gt;. Its posters had caught my eye several times before, and I had listened to the songs, though I never understood how they related to the film. Speaking of songs, I think “Finishing Move” suits &lt;em&gt;Love in the Buff&lt;/em&gt; even better.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Just one “Why don&apos;t you ever come looking for me?”&lt;/p&gt;
&lt;p&gt;No matter how stubborn, how resolute I train myself to be, I can never compare&lt;/p&gt;
&lt;p&gt;Please do not touch me again with the practiced ease you once had&lt;/p&gt;
&lt;p&gt;While I ask myself how you can still manage to hurt me&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Each time Zhi Ming went looking for Chun Jiao, those lyrics returned to me. So what the song describes really does exist, I thought. Because I had not seen &lt;em&gt;Love in a Puff&lt;/em&gt;, the first film, and went directly into &lt;em&gt;Love in the Buff&lt;/em&gt;, the second, I initially found Zhi Ming rather annoying—extremely annoying, in fact.&lt;/p&gt;
&lt;p&gt;Yet I found him annoying because he resembled me, and that made me anxious from somewhere deep inside. He had never grown up. He said he had not matured at all since Form Four, and I seem to be much the same. In high school, I was terribly wrapped up in myself and did little but read novels, as though I could find in them a reason not to take the national college entrance examination. The walls I built around myself then still stand today. I cannot say I have remained completely unchanged, only that I am still self-absorbed.&lt;/p&gt;
&lt;p&gt;I have also become much lazier. At least I used to read thematically, take proper notes, and write reflections after finishing something. Now, even when I feel moved to review a film, I struggle to put the feeling into words.&lt;/p&gt;
&lt;p&gt;My writing is not as good as it used to be. Perhaps I am simply less adolescent and melodramatic than before. Whenever I think that, however, I also have to admit that I am unwilling to change.&lt;/p&gt;
&lt;p&gt;Only when I write without considering anything else does the result truly satisfy me. Perhaps I should find the time to slowly retype what I wrote in the past. I once felt that merely transferring it over would make it seem as though nothing existed in the present—but otherwise, it is as though nothing exists now either.&lt;/p&gt;
&lt;h3&gt;More Than Romance, I Want to Talk About the Bonds Created by Time&lt;/h3&gt;
&lt;p&gt;I used to have an unspoken theory: every sensation and emotion fades with time. Whether it is how I feel after finishing a film or novel, or how I feel about another person, once the direct connection ends—once the film or anime finishes, once I stop speaking to someone—the feeling always grows faint. Inevitably so. For a time, this made me profoundly sad.&lt;/p&gt;
&lt;p&gt;Schopenhauer&apos;s nihilism seems to be built partly upon this insubstantial quality of memory: when we look back on the past, it can seem so insignificant that it is almost as though nothing ever happened.&lt;/p&gt;
&lt;p&gt;Chun Jiao, however, seems to stand firmly against this theory. Her love for Zhi Ming lasts an extraordinarily long time. Even setting affection and romance aside, the two seem bound together by something. Bound, but not tied so tightly that they cannot move. Rather, whenever one of them is about to leave, a thread fastened around their wrist reminds them that the other still exists.&lt;/p&gt;
&lt;p&gt;Even if they meet someone better and better and better, that person remains irreplaceable. Perhaps this is what memory leaves behind. The other person is no longer merely someone you either love or do not love; they have come to represent a long stretch of your past—or rather, a large part of yourself.&lt;/p&gt;
&lt;p&gt;Chun Jiao says that all the interesting parts of herself the older man, played by Xu Zheng, likes—all her strange ideas—were actually caught from Zhi Ming at some point without her noticing.&lt;/p&gt;
&lt;p&gt;When two people spend a long time together, this mutual transmission of habits may bring them closer than any love at first sight ever could. The other person no longer seems to be someone outside the self. They have become part of the self.&lt;/p&gt;
&lt;p&gt;Of course, that is only my rather self-centered interpretation. Their relationship may have been nothing like this at all, because the same bond also caused them pain. Chun Jiao said over the phone, “I like you so, so much, but please stop bothering me.”&lt;/p&gt;
&lt;p&gt;Why does it have to be so complicated?&lt;/p&gt;
&lt;p&gt;The older man was not bad at all. He was practically unbeatable, exactly my type, and funny too. So why did he have to bear it alone?&lt;/p&gt;
</content:encoded></item><item><title>Fanfic</title><link>https://xnnehang.top/en/posts/qingchun-tongrenzhi/</link><guid isPermaLink="true">https://xnnehang.top/en/posts/qingchun-tongrenzhi/</guid><description>Thoughts on Fanfic: androgynous beauty, flaws, and resonance.</description><pubDate>Mon, 08 Jul 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;img src=&quot;../../assets/img/qingchun-tongrenzhi/202407080814636.jpeg&quot; alt=&quot;Fanfic&quot; /&gt;&lt;/p&gt;
&lt;p&gt;The first time I watched a film, I spent the whole time taking screenshots.&lt;/p&gt;
&lt;p&gt;I do not know who said it before, but beautiful girls tend to resemble their fathers more, while handsome boys tend to resemble their mothers more.&lt;/p&gt;
&lt;p&gt;I had felt a little of androgynous beauty in Brigitte Lin before, but hers was ultimately classical; my aesthetic sense could not connect with it directly. But this female lead drove straight into my face.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/img/qingchun-tongrenzhi/202407080814109.jpeg&quot; alt=&quot;Fanfic, screenshot two&quot; /&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“A short story that blends the worlds of fictional characters and real people.”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This refers to the female lead’s fan fiction. The interweaving of reality and fiction is a good idea.&lt;/p&gt;
&lt;p&gt;The film’s overall setting is similar to &lt;em&gt;Sayonara Wild Hearts&lt;/em&gt;. It has a little to say about feminism and being transgender. In the game, the female lead seems to lose her way and become a fake boy. At the reconciliation, she ends by sitting down and playing the guitar as a woman. It still does not quite escape the limits of gender. Although it is a good ending, after the author takes so many drugs along the way, they still do not cross that line. Perhaps that was also meant to accommodate a mainstream audience.&lt;/p&gt;
&lt;p&gt;But the female lead in the film is exactly my favorite type: violent, distant, and unapproachable. At the end, she remains that way. That is not quite accurate; rather, once she discovers that she is a “boy,” the anger that had nowhere to go finally disappears.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/img/qingchun-tongrenzhi/202407080815946.jpeg&quot; alt=&quot;Fanfic, screenshot three&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Beyond that, there does not seem to be much more to discuss, because the plot itself is a little thin.&lt;/p&gt;
&lt;p&gt;But Max is quite an interesting character. At first, he seemed a little annoying to me: endlessly talkative, always seeming to need attention from others.&lt;/p&gt;
&lt;p&gt;He also constantly mocks the female lead’s clothes, intentionally or not, as if he wants her to change back to how she used to be.&lt;/p&gt;
&lt;p&gt;But many details later changed my view of him. The first was at the gym, when he saw the female lead being abused online and became furious. Only then did I realize: oh, fuck, this person likes her. It is the kind of affection Shōya Ishida has in &lt;em&gt;A Silent Voice&lt;/em&gt;. Unfortunately, the female lead is dense as wood—and very aggressive too.&lt;/p&gt;
&lt;p&gt;Still, there was something powerful about the scene where he forcibly presses her back into her seat when she argues with a boy and gets hit. When he confronts the boy, I finally understood that the gym had been foreshadowing this moment.&lt;/p&gt;
&lt;p&gt;And compared with the scene later where the male lead abandons her and runs away—he had spent three months in the hospital after being beaten by thugs, so he is terrified of such situations—it becomes another piece of foreshadowing.&lt;/p&gt;
&lt;p&gt;I only feel that Max is a little like me, though I do not really want to admit it.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/img/qingchun-tongrenzhi/202407080815882.jpeg&quot; alt=&quot;Fanfic, screenshot four&quot; /&gt;&lt;/p&gt;
&lt;p&gt;We all have flaws. Max does not know how to express himself, and the male lead is cowardly, even if there are reasons for it. But in the end, we only want to be with the person whose company feels most comfortable. The angry star and Cinderella are brought together by the words “Your nails are beautiful,” and the film ends with them together forever.&lt;/p&gt;
&lt;p&gt;To be honest, the film is quite shallow. But I was completely absorbed in taking screenshots, so I did not mind much.&lt;/p&gt;
&lt;p&gt;Here are a few more.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/img/qingchun-tongrenzhi/202407080817375.jpeg&quot; alt=&quot;Fanfic, screenshot five&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/img/qingchun-tongrenzhi/202407080818776.jpeg&quot; alt=&quot;Fanfic, screenshot six&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/img/qingchun-tongrenzhi/202407080818704.jpeg&quot; alt=&quot;Fanfic, screenshot seven&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/img/qingchun-tongrenzhi/202407080818010.jpeg&quot; alt=&quot;Fanfic, screenshot eight&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/img/qingchun-tongrenzhi/202407080815426.jpeg&quot; alt=&quot;Fanfic, screenshot nine&quot; /&gt;&lt;/p&gt;
</content:encoded></item><item><title>After “A Year for Ten Thousand Yen”</title><link>https://xnnehang.top/en/posts/yi-nian-yiwan-yuan/</link><guid isPermaLink="true">https://xnnehang.top/en/posts/yi-nian-yiwan-yuan/</guid><description>Thoughts on *Three Days of Happiness*: death, encounters, and ultimate concern.</description><pubDate>Mon, 08 Jul 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;img src=&quot;../../assets/img/covers/yi-nian-yiwan-yuan.jpg&quot; alt=&quot;A Year for Ten Thousand Yen&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Let us start with two side stories.&lt;/p&gt;
&lt;h4&gt;Even someone whose past was worthless can smile at a future full of light.&lt;/h4&gt;
&lt;p&gt;This is what the bookstore owner says to the &quot;human-trafficker uncle&quot; in their exchange in the second volume. I am not sure what relationship that little girl has with him; because it is so unclear, I will call him the &quot;human-trafficker uncle&quot; for now.&lt;/p&gt;
&lt;p&gt;The girl says that, if she had to choose between three billion yen and staying with him, she would choose the latter. When he says that he can buy her anything she wants besides ice cream, she mentions her mother. There is something rather deep in that.&lt;/p&gt;
&lt;p&gt;So here is my hypothesis: the uncle will change because of the girl and go on to live a &quot;bright&quot; life.&lt;/p&gt;
&lt;p&gt;Through this side story and the uncle&apos;s words, the author dissolves one of my original questions. If I had the chance to learn what my future would be like—setting aside whether it was good or bad—would I choose to sell my lifespan?&lt;/p&gt;
&lt;p&gt;The uncle makes one point: although he needs money now, if his future is destitute, he cannot expect to sell it to support his present self. And if his future is truly valuable, then his present hardship becomes less unbearable. In other words, selling it is inadvisable either way, at least in his eyes.&lt;/p&gt;
&lt;p&gt;This was probably the illustrator&apos;s idea in the manga adaptation.&lt;/p&gt;
&lt;h4&gt;Even if we try not to develop feelings for other people, we cannot avoid everyone.&lt;/h4&gt;
&lt;h4&gt;Thirty years without feeling may not be worth living through—not compared with one final month together, nor with three final days free of all care.&lt;/h4&gt;
&lt;h4&gt;Encounters and connections with someone always become an opportunity for us to change.&lt;/h4&gt;
&lt;p&gt;This is what I saw from Miyagi&apos;s point of view in the third volume.&lt;/p&gt;
&lt;p&gt;Perhaps human beings simply cannot bear loneliness. Even when facing someone they know will die soon, they cannot stop themselves from pouring out their feelings, even though they will later face an even sharper loneliness. Each time they make up their minds; each time they cannot help themselves.&lt;/p&gt;
&lt;p&gt;Perhaps Miyagi, had she never met Kusunoki, would have spent thirty years without feeling anything—not for any special reason, but because her other surveillance targets might not all have been as easy to get along with as Kusunoki and that girl, while she herself was only an invisible person. If loneliness counts as a kind of feeling, then perhaps it would have been her only feeling. Then, when her time ended, she would begin life again at nearly fifty. It would not be a good beginning, however one looks at it.&lt;/p&gt;
&lt;p&gt;And meeting someone special may always become an opportunity for her to change, even at nearly fifty.&lt;/p&gt;
&lt;p&gt;From the ending, after Kusunoki has almost paid off her debt and after she works for another three years, she too lives a full and bright life; the rest of her life becomes valuable. In that timeline, she chooses to sell her remaining years, while choosing to spend her final three days with Kusunoki. But perhaps, in another timeline—the life she sold—she met someone else, and Kusunoki became only a memory.&lt;/p&gt;
&lt;p&gt;Seen this way, however far the distance between people stretches, their relationship will always grow faint. Sustaining intense emotion comes at a price. That price may be never feeling anything for anyone again, but as we discussed above, that is impossible.&lt;/p&gt;
&lt;p&gt;And what truly stretches distance is not necessarily space, but time: Naoko and Kizuki, separated across two times.&lt;/p&gt;
&lt;p&gt;Perhaps I should not avoid encounters. Self-study and self-transformation exist, but I want to be saved by a beautiful girl too. I think I said much the same at the end of [[We Who Have No Tomorrow Fell in Love Yesterday]].&lt;/p&gt;
&lt;h4&gt;My own thoughts.&lt;/h4&gt;
&lt;p&gt;I am reminded of a Japanese light novel I read before, &lt;em&gt;Love Comes After Simulation&lt;/em&gt;. The first half of it was very good. It describes a protagonist who can use a simulator to run through possible futures in advance, and even extract the experience he learned from each simulation. He can foresee certain things ahead of time, and the first two romances have considerable depth.&lt;/p&gt;
&lt;p&gt;It does not quite reach ultimate concern in existentialism, but it is not far away.&lt;/p&gt;
&lt;p&gt;That ultimate concern is death.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Three Days of Happiness&lt;/em&gt; suggests that the final three days may be more valuable than the thirty years sold away, or than the original thirty days remaining.&lt;/p&gt;
&lt;p&gt;I do not disagree with this view, but perhaps deep down I still place too much trust in personal agency: as long as one is alive, perhaps a turning point may still exist.&lt;/p&gt;
&lt;p&gt;I think this question should be placed after an earlier one: death, the ultimate concern.&lt;/p&gt;
&lt;p&gt;If I could remain with Miyagi until death, then compared with not knowing when I would die—drifting through life, anxious and afraid of death, and finally dying alone either without noticing or full of fear—I would choose the three days.&lt;/p&gt;
&lt;p&gt;I do not really know how ultimate concern should be resolved, but I think it is related to both the simulator and this work, so I have put them together.&lt;/p&gt;
&lt;p&gt;If I can, I would also like to write something myself.&lt;/p&gt;
</content:encoded></item><item><title>Fuwari Blog Theme Guide</title><link>https://xnnehang.top/en/posts/fuwari-guide/</link><guid isPermaLink="true">https://xnnehang.top/en/posts/fuwari-guide/</guid><description>A guide to the Fuwari-based blog: frontmatter, Markdown, GitHub cards, admonitions, code highlighting, and video embeds.</description><pubDate>Mon, 01 Jul 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;This blog is built with the &lt;strong&gt;Fuwari&lt;/strong&gt; theme and Astro. For anything not covered here, see the &lt;a href=&quot;https://docs.astro.build/&quot;&gt;official Astro documentation&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Post Frontmatter&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;---
title: My First Blog Post
published: 2023-09-09
description: This is the first post of my new Astro blog.
image: ./cover.jpg
tags: [Foo, Bar]
category: Front-end
draft: false
---
&lt;/code&gt;&lt;/pre&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Field&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;title&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Post title&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;published&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Publication date&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;description&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Post summary, shown on the homepage&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;image&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Cover image path. Starts with &lt;code&gt;http://&lt;/code&gt; or &lt;code&gt;https://&lt;/code&gt;: use a remote image; starts with &lt;code&gt;/&lt;/code&gt;: use an image in &lt;code&gt;public&lt;/code&gt;; otherwise: relative to the Markdown file&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;tags&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Post tags&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;category&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Post category&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;draft&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Whether the post is a draft. Drafts do not appear in the production build.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2&gt;Where to Place Post Files&lt;/h2&gt;
&lt;p&gt;Post files belong in &lt;code&gt;src/content/posts/&lt;/code&gt;. You can also create subdirectories to organize posts and assets more clearly:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;src/content/posts/
├── post-1.md
└── post-2/
    ├── cover.png
    └── index.md
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Markdown Examples&lt;/h2&gt;
&lt;h3&gt;Tables&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Size&lt;/th&gt;
&lt;th&gt;Material&lt;/th&gt;
&lt;th&gt;Color&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;9&lt;/td&gt;
&lt;td&gt;Leather&lt;/td&gt;
&lt;td&gt;Brown&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td&gt;Linen&lt;/td&gt;
&lt;td&gt;Natural&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;11&lt;/td&gt;
&lt;td&gt;Glass&lt;/td&gt;
&lt;td&gt;Transparent&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;pre&gt;&lt;code&gt;| Size | Material | Color |
|---|---|---|
| 9 | Leather | Brown |
| 10 | Linen | Natural |
| 11 | Glass | Transparent |
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Horizontal Rules&lt;/h3&gt;
&lt;hr /&gt;
&lt;pre&gt;&lt;code&gt;---
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Inline Math&lt;/h3&gt;
&lt;p&gt;Inline math: $\omega = d\phi / dt$&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Inline math: $\omega = d\phi / dt$
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Display Math&lt;/h3&gt;
&lt;p&gt;$$
I = \int \rho R^{2} dV
$$&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$$
I = \int \rho R^{2} dV
$$
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;GitHub Repository Cards&lt;/h2&gt;
&lt;p&gt;You can add dynamic cards that link to GitHub repositories. Repository information is fetched from the GitHub API when the page loads.&lt;/p&gt;
&lt;p&gt;::github{repo=&quot;saicaca/fuwari&quot;}&lt;/p&gt;
&lt;p&gt;Use &lt;code&gt;::github{repo=&quot;&amp;lt;owner&amp;gt;/&amp;lt;repo&amp;gt;&quot;}&lt;/code&gt; to create a GitHub repository card.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;::github{repo=&quot;saicaca/fuwari&quot;}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Admonitions&lt;/h2&gt;
&lt;p&gt;The following admonition types are supported: &lt;code&gt;note&lt;/code&gt;, &lt;code&gt;tip&lt;/code&gt;, &lt;code&gt;important&lt;/code&gt;, &lt;code&gt;warning&lt;/code&gt;, and &lt;code&gt;caution&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;:::note
Highlights information that users should take into account, even when skimming.
:::&lt;/p&gt;
&lt;p&gt;:::tip
Optional information to help a user be more successful.
:::&lt;/p&gt;
&lt;p&gt;:::important
Crucial information necessary for users to succeed.
:::&lt;/p&gt;
&lt;p&gt;:::warning
Critical content demanding immediate user attention due to potential risks.
:::&lt;/p&gt;
&lt;p&gt;:::caution
Negative potential consequences of an action.
:::&lt;/p&gt;
&lt;h3&gt;Basic Syntax&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;:::note
Highlights information that users should take into account, even when skimming.
:::
:::tip
Optional information to help a user be more successful.
:::
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Custom Titles&lt;/h3&gt;
&lt;p&gt;You can give an admonition a custom title.&lt;/p&gt;
&lt;p&gt;:::note[My Custom Title]
This is a note with a custom title.
:::&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;:::note[MY CUSTOM TITLE]
This is a note with a custom title.
:::
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;GitHub Syntax&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;[!TIP]
GitHub syntax is also supported.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code&gt;&amp;gt; [!NOTE]
&amp;gt; GitHub syntax is also supported.

&amp;gt; [!TIP]
&amp;gt; GitHub syntax is also supported.
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Expressive Code&lt;/h2&gt;
&lt;p&gt;Expressive Code provides syntax highlighting, terminal frames, line markers, diff comparisons, word wrapping, collapsible code, line numbers, and more. See the &lt;a href=&quot;https://expressive-code.com/&quot;&gt;official Expressive Code documentation&lt;/a&gt; for complete usage.&lt;/p&gt;
&lt;h2&gt;Embed Videos in Posts&lt;/h2&gt;
&lt;p&gt;Copy the embed code from YouTube or another platform and paste it directly into a Markdown file.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;---
title: Include Video in the Post
published: 2023-10-19
// ...
---
&amp;lt;iframe width=&quot;100%&quot; height=&quot;468&quot; src=&quot;https://www.youtube.com/embed/5gIf0_xpFPI?si=N1WTorLKL0uwLsU_&quot; title=&quot;YouTube video player&quot; frameborder=&quot;0&quot; allowfullscreen&amp;gt;&amp;lt;/iframe&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;YouTube&lt;/h3&gt;
&lt;p&gt;&amp;lt;iframe width=&quot;100%&quot; height=&quot;468&quot; src=&quot;https://www.youtube.com/embed/5gIf0_xpFPI?si=N1WTorLKL0uwLsU_&quot; title=&quot;YouTube video player&quot; frameborder=&quot;0&quot; allowfullscreen&amp;gt;&amp;lt;/iframe&amp;gt;&lt;/p&gt;
&lt;h3&gt;Bilibili&lt;/h3&gt;
&lt;p&gt;&amp;lt;iframe width=&quot;100%&quot; height=&quot;468&quot; src=&quot;//player.bilibili.com/player.html?bvid=BV1yRdBBsEGZ&amp;amp;page=1&quot; frameborder=&quot;0&quot; allowfullscreen&amp;gt;&amp;lt;/iframe&amp;gt;&lt;/p&gt;
</content:encoded></item><item><title>Near Being, Far Being</title><link>https://xnnehang.top/en/posts/cunzai-zhijin/</link><guid isPermaLink="true">https://xnnehang.top/en/posts/cunzai-zhijin/</guid><description>Changes brought by an urgent experience of death, and the meaning of small happinesses.</description><pubDate>Sat, 29 Jun 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;What Can We Do Before Death? Do We Have Time? Can Someone Come Save Us?&lt;/h1&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/img/cunzai-zhijin/202406290821497.jpeg&quot; alt=&quot;Cover&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;Near Being, Far Being&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;A year is long if you do nothing, but if you truly have something to do, a year seems rather short. Or perhaps you have realized something.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I have already forgotten what the self who asked before the college entrance examination, “What does after the exam feel like? Does it really exist?” truly felt at the time. More than two years have passed without my noticing.&lt;/p&gt;
&lt;p&gt;Two years go quickly when I have little awareness of them.&lt;/p&gt;
&lt;p&gt;When I think about junior and senior year, especially the turmoil that senior year may bring, part of me feels that the one or two years remaining are not very long at all. At the same time, the old unknown attacks me again: what does work actually feel like?&lt;/p&gt;
&lt;p&gt;This is probably it: &lt;strong&gt;a person always feels that the difficulty they face in their present stage—within the next year or two, near or far; distant things cannot be felt immediately, while near things cause anxiety—is incomparable, impossible to get through, and that there is nothing else beyond it.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Of course, an approaching exam in a subject you are not confident about can bring a similar feeling, and the imminent end of winter or summer break works the same way.&lt;/p&gt;
&lt;p&gt;But is this feeling truly impossible to break through? Must we remain forever confined to this one or two years, feeling that the future is hopeless because we cannot see any road beyond it?&lt;/p&gt;
&lt;p&gt;Here I need to step outside and talk about my own experience.&lt;/p&gt;
&lt;h2&gt;A Sudden Urgent Experience of Death, and an Unavoidable Reflection on Death&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;I realized that under ordinary circumstances, ordinary people cannot think this deeply about death.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;A sudden sense that one will die—that death is not distant—can pull a person beyond this boundary.&lt;/strong&gt; In [[Existentialist Reading Notes]], I discussed the theory behind this “urgent experience”: when a deadline is close enough, a person shifts from the “forgetful mode of being” to the “mindful mode of being.”&lt;/p&gt;
&lt;p&gt;For example, one or two weeks ago I found something black, like a mole, on my chest, but I knew it had definitely not been there before. After watching it for a while, I noticed that it seemed to be growing.&lt;/p&gt;
&lt;p&gt;Melanoma. That word came to mind immediately, and malignant skin tumors are among the worst for spreading. For several days, despite having no medical evidence, I suddenly thought that I might have only a few months to live rather than until graduation. When a word more explosive than graduation—death—stood in front of me, the weight of graduation suddenly blurred. &lt;strong&gt;I was thinking about what I could still do if I had only a few months to live; this was not an outline for writing, but complete, unavoidable identification with the thought.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;I did not find an answer, but in only a few days I almost changed my old sleep habits. I gradually began waking at 7:20, perhaps intending to get up even earlier; one morning I rose around seven. I stopped reading novels in bed before sleep. I used to follow my roommate to 8 a.m. classes—getting up after 7:50 and starting class at 8:20, with breakfast more often absent than present.&lt;/p&gt;
&lt;p&gt;That Tuesday I reached the laboratory one step before my automatic-control teacher. She came in behind me, saw me, and said, “Here so early? (￣▽￣)” “Couldn’t sleep. -_-” “Not being able to sleep in is good. If you can’t sleep, get up and study. &amp;lt;(￣︶￣)↗” Perhaps it was that one sentence; over the following days I also arrived early more or less consistently.&lt;/p&gt;
&lt;p&gt;But most importantly, &lt;strong&gt;I suddenly realized that I had no later time left to me. I tried to do today or tomorrow what I had originally planned to do. I wrote code rather than planning what code to write; I read novels and manga rather than forgetting them again and again.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Before, I always placed things on my mental schedule, then some time later casually sighed that I was absolutely the sort of person who never acted according to a plan. Now I also began “eating tomatoes”—using the Pomodoro timer. I have to say that it made me realize when I ought to rest.&lt;/p&gt;
&lt;p&gt;As for that black speck, when I asked about it, someone said it looked like a pimple, a blackhead. While I watched it, it naturally fell away; with it went the heart I had kept suspended for days.&lt;/p&gt;
&lt;h2&gt;Perhaps I Realized That There Is Nothing Except the Present&lt;/h2&gt;
&lt;p&gt;Yet thinking about death ahead of time made me realize that graduation is not the only boundary. To put it bluntly, perhaps I will not live until graduation at all; and if I do live beyond graduation, then there seem to be more things I can do than there are now. I realized that my greatest anxiety is this: &lt;strong&gt;before graduation, I may still be unable to make anything. I may still be unable to make anything that lets me lie flat.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;But then I thought that perhaps I do not need to force myself to make it now. The present may simply be a two-year vacation with comparatively much free time. If I can make it, that is fortunate; if I cannot, I can come back to it later.&lt;/p&gt;
&lt;p&gt;I used to learn and make things under the grand premise of wanting to lie flat, but it seems that in the process I lay flat first =-=.&lt;/p&gt;
&lt;h2&gt;Small Happinesses Are Fine Too&lt;/h2&gt;
&lt;p&gt;With only three months left to live, Kusunoki holds the 300,000 yen he got by selling thirty years of his lifespan, drinks beer, and says that he will use his remaining time to create a splendor he could not have had in the previous thirty years. It sounds like something a gambler would say. But Miyagi sees things clearly. Rather than realizing that one had made mistakes before and believing one can now turn things around, it is better to take the present and slowly accumulate “small happinesses.” Perhaps this is why I write a blog too.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Because we are born with nothing, we can possess everything. — &lt;em&gt;No Game No Life&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Death is forever my best teacher.&lt;/p&gt;
</content:encoded></item><item><title>We Who Have No Tomorrow Fell in Love Yesterday</title><link>https://xnnehang.top/en/posts/meiyou-mingtian/</link><guid isPermaLink="true">https://xnnehang.top/en/posts/meiyou-mingtian/</guid><description>Thoughts at the end of winter break, about death, deadlines, and change.</description><pubDate>Tue, 25 Jun 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;img src=&quot;../../assets/img/covers/meiyou-mingtian.jpg&quot; alt=&quot;We Who Have No Tomorrow Fell in Love Yesterday&quot; /&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;Written on the first day—most of it was deleted, so this may feel a little strange.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;This was the first Japanese light novel I properly moved on to. I found the resistance to reading much lower, and I could almost finish one in a single sitting. Yet language that flows so easily and asks for no thought often lacks a little depth and fullness.&lt;/p&gt;
&lt;p&gt;Still, it gave me an opportunity for a change of mood. If I find myself in something similar again, I can read it again. In that respect, it is a masterpiece.&lt;/p&gt;
&lt;p&gt;I would be willing to revise the book slightly: after the grim reaper sees them for the last time and says, &quot;What am I going to do with you two?&quot;, it would end. It would be nice for the story to stay fixed in a dream.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;PS — continued on the second day. — &quot;Died&quot; at the end of winter break. 2024/2/20&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I think the author put a great deal of work into whether people would regret giving up their lifespan. Just when both characters finally let go and feel no regret, he gives them a rattlesnake watch and turns back time.&lt;/p&gt;
&lt;p&gt;The author says in the preface that it is like comforting words thought of only afterward. I understand that feeling. I often feel regret after I have already left, regret that I did not think things through. In this respect, the protagonists in Murakami&apos;s writing and in &lt;em&gt;The Great Gatsby&lt;/em&gt; have an advantage, because they are pure observers: calm, silent, not offering personal opinions to others, yet often able to say something unexpected at certain moments. Neither the author nor I can manage that, so the author wrote this novel and Murakami wrote &lt;em&gt;On Seeing the 100% Perfect Girl One Beautiful April Morning&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;The author seems to place great weight on &quot;coming to terms with death.&quot; For one moment, I too vaguely set myself the feeling that I would ascend on some day three years from then.&lt;/p&gt;
&lt;p&gt;At bottom, what I want to think about more is idleness. I did not write about it yesterday because I was too exhausted and muddled.&lt;/p&gt;
&lt;p&gt;My situation now is actually very similar to Aiba&apos;s during his first few months. I can do everything I want (read novels, watch films and anime, play games; I can go out too, though I tend not to), and I am also pressed by a deadline. (Aiba knows that he will die on December 26 three years from then; I know that classes begin on February 26. Come to think of it, I have to return to school on the 25th. I had always thought it was the 26th; in the course of talking, another day has disappeared.) With that known outcome, the start of winter break and its later days brought changes in my mood similar to Aiba&apos;s. Later on, I too gradually felt powerless and regretful. Although I kept a schedule similar to the one I had at the beginning, I did begin to doubt it and feel that it never changed. The joy novels initially gave me shifted a little later on.&lt;/p&gt;
&lt;p&gt;Do people inevitably grow bored and regretful after living this way? The grim reaper says that most people begin seeking stimulation later on. A couple of days ago, I did open &lt;em&gt;The Immortal Life&lt;/em&gt;, which I had thought I would never play again. I became absorbed in it for nearly twenty hours, trying to cover my unease with stimulation.&lt;/p&gt;
&lt;p&gt;Aiba happened to choose a road different from other people&apos;s, and Ichinose&apos;s arrival also shifted his life from its ordinary course. Beautiful girls often have the power to change a person, so there is nothing wrong with saying that beautiful girls can save the world. But as I said after &lt;em&gt;Boy&apos;s Babylon&lt;/em&gt;, &quot;There are too many good-looking people and too few interesting ones.&quot; In reality, people as good-looking as Ichinose do exist, and even people as interesting as she is do exist, but the conditions for me to form a connection with one of them exist only in fantasy.&lt;/p&gt;
&lt;p&gt;What should I do if no beautiful girl comes to save me at the end of winter break—go looking on my own? I do not think that is realistic. It would be easy to fall for an online-dating scam, because having worked with TTS, I know that it is now much, much easier for boys to pass as girls.&lt;/p&gt;
&lt;p&gt;Put differently, I am anxious now because winter break is about to end. A few days from now, winter break will end, I will return to school, and I will adapt to life there again. The self who worried about winter break ending will have &quot;died.&quot; Perhaps I will again sink into boundless pleasure and grow anxious as graduation approaches, and then &quot;die&quot; again.&lt;/p&gt;
&lt;p&gt;As a human being, as one of the ordinary people the grim reaper describes, without meeting a beautiful girl who saves me, I will always feel joy when a vacation begins, aimless in the early days, bored in the middle, and seek stimulation later on. Then, near the end, I will feel that I ought to make up everything I missed earlier and begin planning a schedule. So I will &quot;die&quot; again and again, until I finally die.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;A fool always grows wise before dying.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This seems to come from one of Sugaru Miaki&apos;s books. Perhaps it is &lt;em&gt;Three Days of Happiness&lt;/em&gt;: when Miyagi and he have only three days left, everything else seems to lose its color in their eyes. In an instant they seem to reach the state of sages, understanding that only the present and the other person matter, and that everything else does not. Later, after reading the manga adaptation, I wrote about it in [[After “A Year for Ten Thousand Yen”]].&lt;/p&gt;
&lt;p&gt;There is also the phrase &quot;reborn into life.&quot; Perhaps someone is gravely ill, told that they will not live more than three months, and then recovers after those three months. Such an experience makes them different. The question is whether the sage-time left by being &quot;near death&quot; can continue afterward. Or does that sage die as soon as the three-month deadline passes, while a new self begins new joy and aimlessness?&lt;/p&gt;
&lt;p&gt;I have personally had a similar experience. Of course everyone has, though perhaps it did not feel as intense to them as it did to me. When the college entrance examination was a hundred days away, I naively wondered whether the days I lived—with only twenty hours of holiday and twenty-six hours of free time each week—would really end. The past was like an illusion, with only novels left as something real. The future was like a black hole, swallowing every possibility; I could not imagine it.&lt;/p&gt;
&lt;p&gt;During the summer vacation, I did read novels and watch anime, almost everything I could. At university I lamented that time was hard won, and at first I took the initiative to study digital painting, modeling, game development, and neural networks. But as time went by, I found that I gradually valued time less. It was as if that period of strict preparation had merely extended the time of joy. And now I too am gradually sinking into aimlessness. The former sage died before I noticed. What I did afterward was more like the inertia he left behind: it pushed me along for a while, and now it is gone. Until I read this book yesterday, I vaguely began to recognize this—not that I had changed, but that that &quot;I&quot; had already died after the college entrance examination.&lt;/p&gt;
&lt;p&gt;So the urgent thing is to leave &quot;last words&quot; for my winter-break self, though I am sure my future self will probably not reread them carefully.&lt;/p&gt;
&lt;p&gt;I want to be saved by a beautiful girl too. Is that too flippant?&lt;/p&gt;
</content:encoded></item><item><title>Flowers Yet to Bloom</title><link>https://xnnehang.top/en/posts/weijin-zhi-hua/</link><guid isPermaLink="true">https://xnnehang.top/en/posts/weijin-zhi-hua/</guid><description>Thoughts on Flowers Yet to Bloom and the images it completes from Zi Bu Yu.</description><pubDate>Tue, 25 Jun 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;img src=&quot;../../assets/img/covers/weijin-zhi-hua.jpg&quot; alt=&quot;Flowers Yet to Bloom&quot; /&gt;&lt;/p&gt;
&lt;p&gt;I heard its sales were poor because the censors thought its female lead was drawn too young and that it carried a hint of lolicon.&lt;/p&gt;
&lt;p&gt;But I have to say that it holds an irreplaceable place in my heart.&lt;/p&gt;
&lt;p&gt;I place it somewhere among people, ghosts, and fox spirits. The first volume may be a little dull, but by the second I remembered the dreamlike feeling I had when I used to read Xia Da’s &lt;em&gt;Zi Bu Yu&lt;/em&gt;. Dreamlike—like when its heroine dreams that a tiger in a painting leaps at her, and her mother casually drives it away with a stroke of her brush. This book does not have many strange-tale elements, yet the moment when the heroine meets the old woman again moved me.&lt;/p&gt;
&lt;p&gt;An eight-hundred-year-old old woman with the face of a fourteen-year-old, falling in love again after everything she has been through~&lt;/p&gt;
&lt;p&gt;To me, this book completes &lt;em&gt;Zi Bu Yu&lt;/em&gt;. The romantic element missing from &lt;em&gt;Zi Bu Yu&lt;/em&gt; and &lt;em&gt;Natsume’s Book of Friends&lt;/em&gt; is made whole here. I love it; it is beautiful. They are no longer separate works, but part of one complete image.&lt;/p&gt;
&lt;p&gt;Its sales may be low, and perhaps some people will see it only as a simple, sugary romance and forget it quickly. But for me, it may be one of a kind. Every book may have readers like me: people whose attention is suddenly caught, who fall in love without noticing. The feeling is not intense, and that is why it can last. (&lt;em&gt;Zi Bu Yu&lt;/em&gt; and Xia Da; Natsume and summer vacation.) Rather than love, it is a combination of gentleness, imagination, romance, and dreaminess.&lt;/p&gt;
&lt;p&gt;And I thank it for giving me a pleasant evening.&lt;/p&gt;
</content:encoded></item><item><title>Existentialist Reading Notes</title><link>https://xnnehang.top/en/posts/cunzai-zhuyi/</link><guid isPermaLink="true">https://xnnehang.top/en/posts/cunzai-zhuyi/</guid><description>Thoughts on death, memory, and compulsion in existentialism.</description><pubDate>Thu, 20 Jun 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;When I learned that all the complaints I had sent a friend before—about winter break, about death—were actually covered by existentialism&apos;s ultimate concern with death, I found it fascinating. I was also relieved that I was not the only person who thinks about these things.&lt;/p&gt;
&lt;p&gt;This was also the first time I highlighted and annotated at such a high frequency.&lt;/p&gt;
&lt;h1&gt;Part One: Death&lt;/h1&gt;
&lt;h5&gt;1. Near death: changes forced upon an individual by circumstances beyond their control.&lt;/h5&gt;
&lt;p&gt;Heidegger&apos;s two modes of being (not the first time I had seen his name, but the first time I had read about him):&lt;/p&gt;
&lt;p&gt;The forgetful mode of being:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;That is, living in the world of things and immersing oneself in daily trifles. Such a person “drops down a level,” fixates on “idle chatter,” loses themself among “others,” and is directed by the everyday world, caring only about how things ought to be.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This range is still not broad enough. It is precise, but insufficient to encompass everything, so let me extend it a little: 1. following one&apos;s desires, doing only what one wants rather than what one likes, escaping a certain anxiety and regretting it afterward; 2. imagining and sketching a grand future, waiting for it to arrive, while actually doing nothing for it.&lt;/p&gt;
&lt;p&gt;This state is somewhat like one ruled by desire and dopamine. It is easy to slip into, and I always do so without noticing, only to look back and discover that several months, or even half a year, have passed.&lt;/p&gt;
&lt;p&gt;The mindful mode of being (I have to say, the Chinese phrase is difficult both to type and to understand; well done, translator):&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;A person looks at things as they truly are rather than as they ought to be, and finds them novel. To exist in this mode means remaining continuously aware of one&apos;s existence.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This makes me think of Zhexiu in &lt;em&gt;Fighter of the Destiny&lt;/em&gt;. He says, “Either live awake, or die awake.” Compared with Chen Changsheng, who is continually driven by a known death, Zhexiu is a genuine existentialist.&lt;/p&gt;
&lt;p&gt;The discussion turns to death with a known limit. In many ways, it is no different from a winter or summer break whose end date is known. Yet after winter break ends there will be a new beginning, while death is forever held by the unknown. Many philosophers and writers have offered similar views, and with a little humor: “From the moment we are born, we are always dying. The final day&apos;s contribution is not greater than any ordinary day; it merely exposes the latent decay for people to see.”&lt;/p&gt;
&lt;p&gt;Haruki Murakami also wrote in &lt;em&gt;Norwegian Wood&lt;/em&gt;, “Death is not the opposite of life, but a part of it that remains forever.” I do not know whether he realized it himself or borrowed someone else&apos;s words.&lt;/p&gt;
&lt;p&gt;Let us first discuss what it means to be conscious of death&apos;s arrival. Death is the fundamental source of anxiety. We all know that we will eventually die, but we also build protective mechanisms within ourselves and feel that death has nothing to do with us. Most of the time, we know it, yet we do not truly register it.&lt;/p&gt;
&lt;p&gt;How can someone be made clearly aware of it? Here is a hypothesis: your winter break ends in three days.&lt;/p&gt;
&lt;p&gt;Only a definite deadline makes awareness unavoidable. I have always called it “circumstances beyond one&apos;s control,” and I will keep that wording here.&lt;/p&gt;
&lt;p&gt;The deadline cannot be too distant, either. It must be near, pressing, leaving a person unable to contemplate a future death. Only then will it almost inevitably bring an “urgent experience,” a fundamental transformation. Someone formerly desperate for money and status may suddenly find them unimportant; someone who felt aimless may gain a clear purpose; someone who felt life meaningless may become alive again and find living good. (If you are in the forgetful mode of being, you may think I am talking nonsense here. That seems normal to me.) I recorded a similar experience in [[Near Being, Far Being]].&lt;/p&gt;
&lt;p&gt;Scenes like this appear in fiction, but they also happen in real life. Not everyone can experience death, but most people have experienced winter or summer breaks ending many times.&lt;/p&gt;
&lt;p&gt;The changes brought by urgent experience are often positive, but because endings such as the end of winter break are not permanent, they may fail to produce a truly fundamental transformation. After some time, a person may return to how they were.&lt;/p&gt;
&lt;p&gt;When the end of winter break truly stands before me, I suddenly let go and feel that I have reached the mindful mode of being; before that, I had only been in the forgetful mode of being.&lt;/p&gt;
&lt;h5&gt;2. Fiction: it extends the length of life.&lt;/h5&gt;
&lt;p&gt;There is a lot of rambling above, and my ability to organize language is not enough.&lt;/p&gt;
&lt;p&gt;One last thing I want to add is that this kind of “urgent experience” can sometimes be gained through novels and manga, especially long novels. I have to reconsider my previous view. I was almost misled by the common opinion that novels are useless; people who say that are the truly useless ones. Fiction itself can give people this simulated, complete experience—something different from film, something that can only be felt in novels and writing.&lt;/p&gt;
&lt;p&gt;Today, after finishing the manga adaptation of &lt;em&gt;Three Days of Happiness&lt;/em&gt;, I felt the absurdity of how I had been living: looking down on everything, yet accumulating not even the smallest happiness. I read it and was able to critically “return to the starting line.” Perhaps I will keep reading in the future, and keep returning to the start.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;This will be a long series. At present I am very interested in this part about death, though I do not know whether I will have more thoughts later, because I have said almost everything I wanted to say this time. If you finish reading it and feel similarly, you can read this book too.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;I did not take good notes while reading, but after going through it all, many passages still stayed with me.&lt;/p&gt;
&lt;h3&gt;Being:&lt;/h3&gt;
&lt;h5&gt;Do you believe in memory?&lt;/h5&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;“Just as we spend one third of life in dreams, the lifetime taken by death is equally as insignificant as the time spent dreaming.”&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This looks abstract, but I remember its latter half: what has already passed is as insignificant as if it had never existed. Most anime and novels I have watched or read slowly lose their original color in the palace of memory. Feelings that were once intense—I could shout that I love Yunyun, I love Jiuyou—now seem much thinner. As distance grows, the astonishing impression Li Changge once made on me has also dimmed.&lt;/p&gt;
&lt;p&gt;Each time I finish an anime, I am immersed less in the sadness of contrast with reality than in the thought that, once it is over, the image in my heart can no longer remain forever.&lt;/p&gt;
&lt;p&gt;At such times I often complained to my classmates, but thinking about it now, that was a very typical pessimistic view.&lt;/p&gt;
&lt;p&gt;For example, when an eighty-year-old woman looks back on her life, or someone asks her about it, she might pause, then say with light in her eyes that she lived a fulfilled life.&lt;/p&gt;
&lt;p&gt;But if I extended my view to that situation, perhaps I would feel that my life had been a continual losing: this moment loses the previous moment, until in the end nothing remains, including emotion. The insignificance of memory.&lt;/p&gt;
&lt;p&gt;For choosing between these two views, I can recommend a manga, &lt;a href=&quot;https://book.douban.com/subject/35431511/&quot;&gt;Tsunomata no Ichika&lt;/a&gt;, also called &lt;em&gt;A Momentary Flower&lt;/em&gt;. Its character work is somewhat thin, but what the teacher says in the final lesson is worth remembering.&lt;/p&gt;
&lt;h2&gt;Compulsion:&lt;/h2&gt;
&lt;p&gt;A man is going to travel to another place the next day. The night before, he calls women he knows who live there and wants to invite any one of them to dinner. (A sexual invitation.) Only after every one of them rejects him does he let out a long breath and say, “Now I finally have time to open a bottle of wine and read alone.”&lt;/p&gt;
&lt;p&gt;In fact, he has plenty of time like that, but he cannot refuse his own urge to make sexual invitations. Only when circumstances beyond his control intervene can he escape from it.&lt;/p&gt;
&lt;p&gt;I often encounter situations similar to this.&lt;/p&gt;
</content:encoded></item><item><title>Demian</title><link>https://xnnehang.top/en/posts/demian/</link><guid isPermaLink="true">https://xnnehang.top/en/posts/demian/</guid><description>The turning point Hesse explores through Frau Eva is worth revisiting again and again.</description><pubDate>Mon, 01 Apr 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;img src=&quot;../../assets/img/demian/PixPin_2026-08-08_23-27-40.jpg&quot; alt=&quot;Demian&quot; /&gt;&lt;/p&gt;
&lt;p&gt;This is one of my fixations. It connects with Larry and Watanabe, though Murakami and Maugham rather cleverly use asceticism to obscure the turning points that transform them.&lt;/p&gt;
&lt;p&gt;The turning point Hesse explores through Frau Eva is worth revisiting again and again.&lt;/p&gt;
&lt;p&gt;The long opening stretch is very dark. I have already moved beyond that period, yet rereading it still stirs something in me. I really am a lot like Hesse.&lt;/p&gt;
</content:encoded></item><item><title>The Girlfriend at the End of the World</title><link>https://xnnehang.top/en/posts/shijie-jintou-de-nvyou/</link><guid isPermaLink="true">https://xnnehang.top/en/posts/shijie-jintou-de-nvyou/</guid><description>A style I love: it showed me that twenty-first-century Chinese literature holds more than pain literature and realism—mono no aware, for one.</description><pubDate>Tue, 26 Mar 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;img src=&quot;../../assets/img/shijie-jintou-de-nvyou/PixPin_2026-08-08_23-30-49.jpg&quot; alt=&quot;The Girlfriend at the End of the World&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;The Girlfriend at the End of the World&lt;/em&gt; has something of the Murakami translated by Lin Shaohua. It also feels a little like Lu Nei.&lt;/p&gt;
&lt;p&gt;Terasetsu’s piece is exceptional.&lt;/p&gt;
&lt;p&gt;Every story ends with a trace of sadness and solitude. &lt;em&gt;Mono no aware.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;The author’s style does not yet seem settled, but it is truly good. I hope they stay healthy and happy.&lt;/p&gt;
&lt;p&gt;I am not good at reading short stories, so I read it on and off for a long time. When I finished it, I felt that it broke my long-held impression that China has only realist literature and fiction.&lt;/p&gt;
&lt;p&gt;A revision to my view: the lubricant that keeps me reading is not romance, but girls. A-Bao proves that can work too.&lt;/p&gt;
</content:encoded></item><item><title>Using OBS with VTube Studio: Be a Vtuber</title><link>https://xnnehang.top/en/posts/obs-vtube-studio-vtuber-guide/</link><guid isPermaLink="true">https://xnnehang.top/en/posts/obs-vtube-studio-vtuber-guide/</guid><description>A guide to using OBS together with VTube Studio for livestreaming or video recording.</description><pubDate>Tue, 30 Jan 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;:::note[About the Images]
Because this was uploaded early, the screenshots in this post are heavily compressed and rather blurry, but they remain clear enough to follow the steps.
:::&lt;/p&gt;
&lt;p&gt;These settings can be used for livestreaming or recording video.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/img/covers/202510301542286.jpg&quot; alt=&quot;VTube Studio with OBS&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;Step 1. Configure VTube Studio&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Enable face tracking:&lt;/strong&gt; Double-click to open the settings menu.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/img/covers/202510301542124.jpg&quot; alt=&quot;Enable face tracking in VTube Studio&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Choose &lt;code&gt;pickcolor&lt;/code&gt; for the background:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/img/covers/202510301541875.jpg&quot; alt=&quot;Choose ColorPicker for the VTube Studio background&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Enable transparent streaming:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/img/covers/202510301541004.jpg&quot; alt=&quot;Enable transparent streaming in VTube Studio&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;Step 2. Configure OBS&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Add a game capture source:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/img/covers/202510301541665.jpg&quot; alt=&quot;Add game capture in OBS&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Choose Create new:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/img/covers/202510301541481.jpg&quot; alt=&quot;Create a new OBS source&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Configure it as follows:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/img/covers/202510301541406.jpg&quot; alt=&quot;OBS settings&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/img/covers/202510301541539.jpg&quot; alt=&quot;OBS settings, continued&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Confirm the settings. You can freely drag the window and adjust it into something like this:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/img/covers/202510301541799.jpg&quot; alt=&quot;OBS with VTube Studio&quot; /&gt;&lt;/p&gt;
</content:encoded></item><item><title>Fengxin Is a Good Name</title><link>https://xnnehang.top/en/posts/fengxin-lou/</link><guid isPermaLink="true">https://xnnehang.top/en/posts/fengxin-lou/</guid><description>A ten-year dream of Yangzhou: the people and moments in Fengxin Tower.</description><pubDate>Mon, 17 Oct 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;img src=&quot;../../assets/img/covers/fengxin-lou.jpg&quot; alt=&quot;Fengxin Tower&quot; /&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Ten years, a dream in Yangzhou; I won but a fickle name among courtesans.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I became a Minister of Personnel and spent every day with Xiyun. I actually prefer a freer life, but being able to stay with Xiyun was quite nice too. At worst, I could resign early, then take Xiyun to the places I had never visited before. Guan Xianzi also served as an official with me. Her blindness made me worry, but with her character and martial skill, there was no need to fear that anyone would bully her. I have always felt warmly toward Guan Xianzi, who had been betrothed to me since childhood. I hope Xie Xin takes more walks with her for me, and that they eat zongzi together during the Dragon Boat Festival. Li Shuangshuang and Yiyi have wandered the world together. I envy their carefree roaming—from the south of West Lake to the north of Mount Tai. I hope I can meet them again someday. I could tell that Yiyi liked me, but I never said so. When I carried Shuangshuang down the mountain, I did have some improper thoughts, but in the end I still could not refuse Xiyun’s devotion. When Guan Xianzi said that, if my martial arts never recovered, she would protect me for a lifetime, I was truly moved. I am grateful that she really did remain by my side in the end. Xie Xin, Xie Xin, do not neglect those around you: Guan Xianzi, chestnut cakes, and Xiyun. I did not forget Huang Chan. I hope time lets Shiyuehua reconcile with her. It would be nice if they could open a pharmacy together, though that is unlikely.&lt;/p&gt;
&lt;p&gt;In the end, I will still miss it: the ten years in the pleasure house, the little interactions and moments of feeling with them. I am glad I bought a qin for Nie Xiang then. I wonder who she will play it for in the future. When she plays “Flowing Water” again, will she think of me?&lt;/p&gt;
</content:encoded></item></channel></rss>