[{"data":1,"prerenderedAt":1842},["ShallowReactive",2],{"blog-article-/en/blog/foxycape-pdf-obsidian":3,"blog-list-en":270},{"id":4,"title":5,"body":6,"config":254,"date":255,"description":256,"draft":257,"extension":258,"image":254,"meta":259,"navigation":260,"path":261,"seo":262,"stem":263,"tags":264,"toolbar":254,"translationKey":268,"updated":255,"__hash__":269},"blog/en/blog/foxycape-pdf-obsidian.md","Foxycape PDF — A PDF Reader for Obsidian That Stays Connected to Your Notes",{"type":7,"value":8,"toc":237},"minimark",[9,17,23,26,31,34,53,56,60,65,68,74,78,81,86,90,93,121,126,130,133,138,143,147,159,164,168,171,176,180,183,188,192,199,204,208,211,216,221,225,232],[10,11,12],"p",{},[13,14],"img",{"alt":15,"src":16},"Foxycape PDF","https://cdn.linghuxiong.com/resources/obsidian/introduce/logo-64x64.png",[18,19,20],"blockquote",{},[10,21,22],{},"A PDF reader for Obsidian that stays connected to your notes — highlights, citations, and deep links that take you back to the source.",[24,25],"hr",{},[27,28,30],"h2",{"id":29},"why","Why",[10,32,33],{},"Reading PDFs inside Obsidian often breaks the note-taking loop:",[35,36,37,41,44,47,50],"ul",{},[38,39,40],"li",{},"Highlights stay in the PDF; your vault notes stay elsewhere.",[38,42,43],{},"Grabbing a figure usually means a blurry screenshot.",[38,45,46],{},"Pasted quotes and images rarely point back to the exact page or region.",[38,48,49],{},"Light PDF pages feel harsh in a dark vault theme.",[38,51,52],{},"Switching readers can break page/selection links you already use.",[10,54,55],{},"Foxycape PDF addresses these gaps without asking you to leave Obsidian.",[27,57,59],{"id":58},"features","Features",[61,62,64],"h3",{"id":63},"highlight-note-sync","Highlight → note sync",[10,66,67],{},"Instead of leaving highlights stranded in the PDF, each new highlight can create or update a Markdown note with the same name, append the excerpt with a back-link, and optionally open that note in a split pane. Turn it off anytime in settings.",[10,69,70],{},[13,71],{"alt":72,"src":73},"","https://cdn.linghuxiong.com/resources/obsidian/introduce/highlight-notes.gif",[61,75,77],{"id":76},"extract-embedded-images","Extract embedded images",[10,79,80],{},"Skip blurry screenshots. Hover an embedded image (or use the touch control on mobile) to preview, copy, or download the original asset.",[10,82,83],{},[13,84],{"alt":72,"src":85},"https://cdn.linghuxiong.com/resources/obsidian/introduce/embed-images.gif",[61,87,89],{"id":88},"cite-text-and-images-then-jump-back","Cite text and images, then jump back",[10,91,92],{},"Citations stay tied to the source, so you can jump back from the note later:",[35,94,95,110,113],{},[38,96,97,98,102,103,102,106,109],{},"Copy a text citation as Markdown with a deep link (",[99,100,101],"code",{},"#page="," / ",[99,104,105],{},"#selection=",[99,107,108],{},"#markId=",").",[38,111,112],{},"Copy an image citation; paste into Markdown to save a PNG next to the PDF and insert a clickable link.",[38,114,115,116,120],{},"Right-click the note image → ",[117,118,119],"strong",{},"Open in Foxycape"," to return to the page and highlight the original region.",[10,122,123],{},[13,124],{"alt":72,"src":125},"https://cdn.linghuxiong.com/resources/obsidian/introduce/cite-and-back.gif",[61,127,129],{"id":128},"theme-aware-pdf-pages","Theme-aware PDF pages",[10,131,132],{},"Bright PDF pages can fight a dark vault. Optionally remap grayscale vector colors to your theme foreground/background (BETA) — for all themes, dark only, or light only. Color artwork stays as-is.",[10,134,135],{},[13,136],{"alt":72,"src":137},"https://cdn.linghuxiong.com/resources/obsidian/introduce/theme-adapt.gif",[10,139,140],{},[13,141],{"alt":72,"src":142},"https://cdn.linghuxiong.com/resources/obsidian/introduce/theme-adapt-dark.gif",[61,144,146],{"id":145},"compatible-with-obsidians-built-in-pdf-links","Compatible with Obsidian’s built-in PDF links",[10,148,149,150,152,153,155,156,158],{},"Switching readers shouldn’t break the links you already have. Foxycape understands Obsidian-style ",[99,151,101],{}," and ",[99,154,105],{},", can become the default PDF viewer, reuses an open tab when possible, and adds ",[99,157,108],{}," for precise highlight jumps.",[10,160,161],{},[13,162],{"alt":72,"src":163},"https://cdn.linghuxiong.com/resources/obsidian/introduce/compat-links.gif",[61,165,167],{"id":166},"highlights-and-highlight-list","Highlights and highlight list",[10,169,170],{},"Highlighter, wavy underline, and straight underline with custom colors. Browse highlights in a list — filter, sort, jump, or delete.",[10,172,173],{},[13,174],{"alt":72,"src":175},"https://cdn.linghuxiong.com/resources/obsidian/introduce/annotations.gif",[61,177,179],{"id":178},"smart-copy-unwrap-soft-line-breaks","Smart copy — unwrap soft line breaks",[10,181,182],{},"PDF lines often insert hard breaks mid-sentence. Select text and copy as usual: Foxycape strips those soft wraps so the paste reads as continuous prose, while keeping real paragraph breaks.",[10,184,185],{},[13,186],{"alt":72,"src":187},"https://cdn.linghuxiong.com/resources/obsidian/introduce/smart-copy.gif",[61,189,191],{"id":190},"navigation-and-search","Navigation and search",[10,193,194,195,198],{},"Outline (TOC), page thumbnails, page picker, and in-document search (",[99,196,197],{},"Mod+F",") with case / diacritic / whole-word options. Search uses the PDF text layer (no OCR).",[10,200,201],{},[13,202],{"alt":72,"src":203},"https://cdn.linghuxiong.com/resources/obsidian/introduce/navigate-search.gif",[61,205,207],{"id":206},"reading-layout","Reading layout",[10,209,210],{},"Zoom (auto / page width / percentages), vertical or horizontal scroll, single / facing / book layout, page rotation, password-protected PDFs. Works on desktop and mobile.",[10,212,213],{},[13,214],{"alt":72,"src":215},"https://cdn.linghuxiong.com/resources/obsidian/introduce/layout.gif",[10,217,218],{},[13,219],{"alt":72,"src":220},"https://cdn.linghuxiong.com/resources/obsidian/introduce/layout-1.gif",[61,222,224],{"id":223},"set-as-the-default-pdf-reader","Set as the default PDF reader",[10,226,227,228,231],{},"For the smoothest experience—deep links, highlights, and theme-aware pages—turn on ",[117,229,230],{},"Use as default PDF viewer"," in Foxycape settings so Obsidian opens PDFs with Foxycape by default.",[10,233,234],{},[13,235],{"alt":72,"src":236},"https://cdn.linghuxiong.com/resources/obsidian/introduce/set-default.gif",{"title":72,"searchDepth":238,"depth":238,"links":239},2,[240,241],{"id":29,"depth":238,"text":30},{"id":58,"depth":238,"text":59,"children":242},[243,245,246,247,248,249,250,251,252,253],{"id":63,"depth":244,"text":64},3,{"id":76,"depth":244,"text":77},{"id":88,"depth":244,"text":89},{"id":128,"depth":244,"text":129},{"id":145,"depth":244,"text":146},{"id":166,"depth":244,"text":167},{"id":178,"depth":244,"text":179},{"id":190,"depth":244,"text":191},{"id":206,"depth":244,"text":207},{"id":223,"depth":244,"text":224},null,"2026-08-11","Highlights, citations, and deep links that take you back to the source—Foxycape PDF keeps reading and note-taking in Obsidian in one loop.",false,"md",{},true,"/en/blog/foxycape-pdf-obsidian",{"title":5,"description":256},"en/blog/foxycape-pdf-obsidian",[265,266,267],"Obsidian","PDF","Foxycape","foxycape-pdf-obsidian","L_AUpMWkPG4lq81x2xp5Ba69s6Hs9_535gYvgw-Amq0",[271,436],{"id":4,"title":5,"body":272,"config":254,"date":255,"description":256,"draft":257,"extension":258,"image":254,"meta":433,"navigation":260,"path":261,"seo":434,"stem":263,"tags":435,"toolbar":254,"translationKey":268,"updated":255,"__hash__":269},{"type":7,"value":273,"toc":418},[274,278,282,284,286,288,300,302,304,306,308,312,314,316,320,322,324,340,344,346,348,352,356,358,366,370,372,374,378,380,382,386,388,392,396,398,400,404,408,410,414],[10,275,276],{},[13,277],{"alt":15,"src":16},[18,279,280],{},[10,281,22],{},[24,283],{},[27,285,30],{"id":29},[10,287,33],{},[35,289,290,292,294,296,298],{},[38,291,40],{},[38,293,43],{},[38,295,46],{},[38,297,49],{},[38,299,52],{},[10,301,55],{},[27,303,59],{"id":58},[61,305,64],{"id":63},[10,307,67],{},[10,309,310],{},[13,311],{"alt":72,"src":73},[61,313,77],{"id":76},[10,315,80],{},[10,317,318],{},[13,319],{"alt":72,"src":85},[61,321,89],{"id":88},[10,323,92],{},[35,325,326,334,336],{},[38,327,97,328,102,330,102,332,109],{},[99,329,101],{},[99,331,105],{},[99,333,108],{},[38,335,112],{},[38,337,115,338,120],{},[117,339,119],{},[10,341,342],{},[13,343],{"alt":72,"src":125},[61,345,129],{"id":128},[10,347,132],{},[10,349,350],{},[13,351],{"alt":72,"src":137},[10,353,354],{},[13,355],{"alt":72,"src":142},[61,357,146],{"id":145},[10,359,149,360,152,362,155,364,158],{},[99,361,101],{},[99,363,105],{},[99,365,108],{},[10,367,368],{},[13,369],{"alt":72,"src":163},[61,371,167],{"id":166},[10,373,170],{},[10,375,376],{},[13,377],{"alt":72,"src":175},[61,379,179],{"id":178},[10,381,182],{},[10,383,384],{},[13,385],{"alt":72,"src":187},[61,387,191],{"id":190},[10,389,194,390,198],{},[99,391,197],{},[10,393,394],{},[13,395],{"alt":72,"src":203},[61,397,207],{"id":206},[10,399,210],{},[10,401,402],{},[13,403],{"alt":72,"src":215},[10,405,406],{},[13,407],{"alt":72,"src":220},[61,409,224],{"id":223},[10,411,227,412,231],{},[117,413,230],{},[10,415,416],{},[13,417],{"alt":72,"src":236},{"title":72,"searchDepth":238,"depth":238,"links":419},[420,421],{"id":29,"depth":238,"text":30},{"id":58,"depth":238,"text":59,"children":422},[423,424,425,426,427,428,429,430,431,432],{"id":63,"depth":244,"text":64},{"id":76,"depth":244,"text":77},{"id":88,"depth":244,"text":89},{"id":128,"depth":244,"text":129},{"id":145,"depth":244,"text":146},{"id":166,"depth":244,"text":167},{"id":178,"depth":244,"text":179},{"id":190,"depth":244,"text":191},{"id":206,"depth":244,"text":207},{"id":223,"depth":244,"text":224},{},{"title":5,"description":256},[265,266,267],{"id":437,"title":438,"body":439,"config":254,"date":1830,"description":1831,"draft":257,"extension":258,"image":254,"meta":1832,"navigation":260,"path":1833,"seo":1834,"stem":1835,"tags":1836,"toolbar":254,"translationKey":1840,"updated":1830,"__hash__":1841},"blog/en/blog/zero-hallucination-qa.md","How I Built Zero-Hallucination Q&A in Our Reader",{"type":7,"value":440,"toc":1796},[441,447,460,462,466,473,478,482,500,505,516,521,555,558,562,579,586,590,605,610,647,654,658,671,696,701,818,836,842,844,848,855,870,877,897,903,905,909,912,918,920,924,947,957,1017,1020,1031,1040,1047,1049,1053,1064,1070,1077,1081,1088,1096,1103,1107,1117,1160,1171,1177,1179,1183,1197,1205,1211,1214,1249,1259,1267,1273,1280,1284,1293,1299,1310,1312,1316,1322,1326,1333,1337,1360,1367,1369,1373,1379,1437,1443,1445,1449,1456,1475,1479,1499,1510,1512,1516,1527,1530,1553,1564,1570,1572,1576,1591,1602,1604,1608,1629,1640,1642,1646,1665,1671,1673,1677,1764,1771,1782],[10,442,443],{},[13,444],{"alt":445,"src":446},"Cover: Zero-hallucination Q&A","https://cdn.linghuxiong.com/resources/snapshots/ai-chat-cover.png",[18,448,449],{},[10,450,451,452,455,456,459],{},"This post shares how we implemented ",[117,453,454],{},"zero-hallucination Q&A"," in our AI reader: answers are strictly grounded in the text of the book you have open, and key claims can be ",[117,457,458],{},"traced in one click"," to the exact passage. If you are building AI reading, document Q&A, or RAG-style apps, we hope three iterations of lessons and the final architecture are useful.",[24,461],{},[27,463,465],{"id":464},"i-evolution-in-three-stages","I. Evolution in three stages",[10,467,468,469,472],{},"Zero-hallucination Q&A was not designed perfectly on day one. It evolved under tension between ",[117,470,471],{},"cost, latency, and accuracy",". Below is a chronological view of three stages—useful context for why the current architecture looks the way it does.",[474,475],"mermaid",{":config":476,"code":477},"config","flowchart%20LR%0A%20%20%20%20P1%5BStage%201%3A%20Full-text%20dump%5D%20--%3E%20P2%5BStage%202%3A%20LLM%20key-sentence%20extract%5D%0A%20%20%20%20P2%20--%3E%20P3%5BStage%203%3A%20Segment%20index%20%2B%20Tool%20retrieval%5D%0A%20%20%20%20P1%20-.-%3E%7CSlow%2C%20costly%2C%20inaccurate%20on%20long%20books%7C%20X1%5BRetired%5D%0A%20%20%20%20P2%20-.-%3E%7CLost%20detail%2C%20still%20slow%7C%20X2%5BRetired%5D%0A%20%20%20%20P3%20--%3E%7CCurrent%7C%20OK%5BZero%20hallucination%20%2B%20traceable%5D",[61,479,481],{"id":480},"stage-1-dump-the-full-book-into-context-simplestand-first-to-break","Stage 1: Dump the full book into context (simplest—and first to break)",[10,483,484,487,488,491,492,495,496,499],{},[117,485,486],{},"Approach:"," When a user opens a book and asks a question, put ",[117,489,490],{},"all extracted body text"," into the system prompt or user message and let the chat model answer. If the book exceeds about ",[117,493,494],{},"400k characters",", ",[117,497,498],{},"hard-truncate","—only the beginning is kept; later chapters are invisible to the model.",[10,501,502],{},[117,503,504],{},"Pros:",[35,506,507,510,513],{},[38,508,509],{},"Very low implementation cost; almost no preprocessing;",[38,511,512],{},"Works reasonably on short books and simple documents—the model really “saw the whole book”;",[38,514,515],{},"Simple UX: ask and get an answer, no “please wait while we analyze” state.",[10,517,518],{},[117,519,520],{},"Cons (quickly unacceptable):",[35,522,523,529,535,545],{},[38,524,525,528],{},[117,526,527],{},"Slow responses:"," Every question resends a huge payload; time-to-first-token and total latency grow with book length;",[38,530,531,534],{},[117,532,533],{},"High token cost:"," You pay for the full book input on every question;",[38,536,537,540,541,544],{},[117,538,539],{},"Long books distort badly:"," After 400k characters, the second half, appendices, and conclusions may as well not exist—and the UI often ",[117,542,543],{},"does not clearly say"," truncation happened;",[38,546,547,550,551,554],{},[117,548,549],{},"Zero retrieval granularity:"," The model must “find a needle in a haystack” across hundreds of thousands of characters—easy to miss details and easier to produce ",[117,552,553],{},"plausible-sounding summaries with no basis","—exactly what reading apps must avoid.",[10,556,557],{},"Stage 1 is fine for an MVP, not for a product-grade solution.",[61,559,561],{"id":560},"stage-2-use-a-lighter-llm-to-extract-key-sentences-compress-contextbut-too-aggressively","Stage 2: Use a lighter LLM to extract key sentences (compress context—but too aggressively)",[10,563,564,566,567,570,571,574,575,578],{},[117,565,486],{}," Before Q&A (or on first open), run a ",[117,568,569],{},"cheaper model"," over the body: split by spine chapter (or chunk the whole book), extract ",[117,572,573],{},"key sentences",", keep position tags like ",[99,576,577],{},"[fFile-start-end]",", then concatenate excerpts into a shorter context for later Q&A.",[10,580,581,582,585],{},"Typical pipeline: ",[117,583,584],{},"Extract → Cache → Chat",". Extract once (offline or on demand), store a “key sentence bundle,” reuse it for every question—same idea as many document-QA prototypes that compress first, then answer.",[10,587,588],{},[117,589,504],{},[35,591,592,599,602],{},[38,593,594,595,598],{},"Each question sends ",[117,596,597],{},"much less text","; per-request token use drops vs. stage 1;",[38,600,601],{},"Preprocessing can be cached; no re-extract per question on the same book;",[38,603,604],{},"Position tags lay groundwork for citations.",[10,606,607],{},[117,608,609],{},"Cons (still fails on long books):",[35,611,612,618,628,637],{},[38,613,614,617],{},[117,615,616],{},"Heavy detail loss:"," “Key sentences” are model-selected; qualifiers, counterexamples, and argument chains are often dropped—answers become “correct but one-sided”;",[38,619,620,623,624,627],{},[117,621,622],{},"Context still large on long books:"," Even key-sentence bundles for big works are sizable—latency and cost are ",[117,625,626],{},"eased, not solved",";",[38,629,630,633,634,627],{},[117,631,632],{},"Double LLM error:"," Extraction may miss; Q&A may misread excerpts—errors ",[117,635,636],{},"stack",[38,638,639,642,643,646],{},[117,640,641],{},"Static context:"," Whether the user asks about one chapter or whole-book structure, the model always gets the ",[117,644,645],{},"same pre-extracted blob","—no dynamic narrowing by question.",[10,648,649,650,653],{},"Lesson: the issue is not “whether we compress,” but ",[117,651,652],{},"whether compression is on-demand and whether we can return to source text",".",[61,655,657],{"id":656},"stage-3-segment-index-tool-retrieval-on-demand-source-text-back-current","Stage 3: Segment index + Tool retrieval on demand + source text back (current)",[10,659,660,662,663,670],{},[117,661,486],{}," Inspired by ",[664,665,669],"a",{"href":666,"rel":667},"https://github.com/VectifyAI/PageIndex",[668],"nofollow","PageIndex",". Vs. stage 2, three core shifts:",[672,673,674,680,690],"ol",{},[38,675,676,679],{},[117,677,678],{},"Preprocessing produces a structured index"," (TOC-level summaries + exact character spans), not excerpts used directly as Q&A context;",[38,681,682,685,686,689],{},[117,683,684],{},"Each question uses Tool Calling to retrieve on demand",", then ",[117,687,688],{},"pulls source text with position tags"," to answer;",[38,691,692,695],{},[117,693,694],{},"System prompt + frontend"," enforce citation format and support click-to-jump highlights in the reader.",[10,697,698],{},[117,699,700],{},"Three-stage comparison:",[702,703,704,723],"table",{},[705,706,707],"thead",{},[708,709,710,714,717,720],"tr",{},[711,712,713],"th",{},"Dimension",[711,715,716],{},"Stage 1 (full dump)",[711,718,719],{},"Stage 2 (key sentences)",[711,721,722],{},"Stage 3 (current)",[724,725,726,745,759,773,787,804],"tbody",{},[708,727,728,732,735,738],{},[729,730,731],"td",{},"Context per question",[729,733,734],{},"Whole book (or truncated front half)",[729,736,737],{},"Pre-extracted key sentences",[729,739,740,741,744],{},"Only ",[117,742,743],{},"source"," snippets relevant to the question",[708,746,747,750,753,756],{},[729,748,749],{},"Long-book accuracy",[729,751,752],{},"Collapses past ~400k chars",[729,754,755],{},"Depends on extraction; loses detail",[729,757,758],{},"Retrieve by TOC/span; no hard full-book truncate",[708,760,761,764,767,770],{},[729,762,763],{},"Response speed",[729,765,766],{},"Slow",[729,768,769],{},"Somewhat better; long books still slow",[729,771,772],{},"Retrieve + short context—noticeably faster",[708,774,775,778,781,784],{},[729,776,777],{},"Token cost",[729,779,780],{},"Very high",[729,782,783],{},"Medium-high",[729,785,786],{},"Amortized preprocess + pay per need",[708,788,789,792,795,798],{},[729,790,791],{},"Traceability",[729,793,794],{},"Weak (hard to cite)",[729,796,797],{},"Tags exist but content is secondarily filtered",[729,799,800,801],{},"Footnotes map to ",[117,802,803],{},"real source spans",[708,805,806,809,812,815],{},[729,807,808],{},"Engineering complexity",[729,810,811],{},"Low",[729,813,814],{},"Medium",[729,816,817],{},"High",[10,819,820,823,824,827,828,831,832,835],{},[117,821,822],{},"Why we stopped at stage 3:"," For reading, zero hallucination is not “show the model as much text as possible,” but ",[117,825,826],{},"“before answering, fetch source evidence for the question.”"," Stages 1–2 fought ",[117,829,830],{},"context size","; stage 3 splits the pipeline into ",[117,833,834],{},"index (preprocess) → retrieve (Tool) → evidence (source) → answer (constrained generation)","—balancing accuracy, cost, and traceability.",[10,837,838,839,653],{},"Below we detail ",[117,840,841],{},"stage 3",[24,843],{},[27,845,847],{"id":846},"ii-problem-statement-in-book-qa-hallucination-hurts-more-than-in-generic-chat","II. Problem statement: In book Q&A, hallucination hurts more than in generic chat",[10,849,850,851,854],{},"Users forgive occasional errors in a general chatbot. In ",[117,852,853],{},"book Q&A",", the cost is higher:",[35,856,857,864,867],{},[38,858,859,860,863],{},"Users ask what ",[117,861,862],{},"this book"," says—not what lives in the model’s parametric memory;",[38,865,866],{},"A plausible-sounding “view from the book” can mislead notes, citations, and reshares;",[38,868,869],{},"Without sources, users cannot verify—trust is hard to build.",[10,871,872,873,876],{},"So “zero hallucination” becomes three ",[117,874,875],{},"enforceable"," rules:",[672,878,879,885,891],{},[38,880,881,884],{},[117,882,883],{},"Book questions must query the book first:"," Anything plausibly about the open book must go through retrieval (Tool) before an answer;",[38,886,887,890],{},[117,888,889],{},"Answers must be traceable:"," Key claims carry position tags the UI can parse and jump to;",[38,892,893,896],{},[117,894,895],{},"Say when you cannot find it:"," If the book does not contain it, say so—do not dress up general knowledge as “what the book says.”",[10,898,899,900,902],{},"The rest follows ",[117,901,841],{}," data flow and how these rules are implemented.",[24,904],{},[27,906,908],{"id":907},"iii-architecture-preprocess-tool-retrieval-constrained-generation-clickable-citations","III. Architecture: Preprocess → Tool retrieval → Constrained generation → Clickable citations",[474,910],{":config":476,"code":911},"flowchart%20TB%0A%20%20%20%20subgraph%20prep%20%5BOffline%20%2F%20first-time%20preprocess%5D%0A%20%20%20%20%20%20%20%20A%5BSplit%20book%20by%20TOC%20or%20length%5D%20--%3E%20B%5BLLM%20segment%20summaries%5D%0A%20%20%20%20%20%20%20%20B%20--%3E%20C%5BPersist%20Segment%20cache%20locally%5D%0A%20%20%20%20end%0A%0A%20%20%20%20subgraph%20ask%20%5BUser%20question%5D%0A%20%20%20%20%20%20%20%20D%5BUser%20input%5D%20--%3E%20E%7BSegment%20cache%20exists%3F%7D%0A%20%20%20%20%20%20%20%20E%20--%3E%7CNo%7C%20F%5BExtract%20full%20text%20%2F%20ask%20to%20preprocess%5D%0A%20%20%20%20%20%20%20%20F%20--%3E%20prep%0A%20%20%20%20%20%20%20%20E%20--%3E%7CYes%7C%20G%5BRegister%20Tool%20Calling%5D%0A%20%20%20%20end%0A%0A%20%20%20%20subgraph%20retrieve%20%5BTool%20retrieval%5D%0A%20%20%20%20%20%20%20%20G%20--%3E%20H%7BQuestion%20type%7D%0A%20%20%20%20%20%20%20%20H%20--%3E%7COverview%20%2F%20review%7C%20I%5Bget_full_book_segment_summaries%5D%0A%20%20%20%20%20%20%20%20H%20--%3E%7CFacts%20%2F%20people%20%2F%20chapter%7C%20J%5Bget_related_segment_summaries%5D%0A%20%20%20%20%20%20%20%20J%20--%3E%20K%5BLLM%20picks%20segment%20IDs%20from%20summary%20catalog%5D%0A%20%20%20%20%20%20%20%20K%20--%3E%20L%5BFetch%20source%20by%20span%20%2B%20position%20tags%5D%0A%20%20%20%20%20%20%20%20I%20--%3E%20M%5BConcatenate%20all%20segment%20summaries%5D%0A%20%20%20%20end%0A%0A%20%20%20%20subgraph%20answer%20%5BGenerate%20%26%20display%5D%0A%20%20%20%20%20%20%20%20L%20--%3E%20N%5BTool%20results%20back%20to%20model%5D%0A%20%20%20%20%20%20%20%20M%20--%3E%20N%0A%20%20%20%20%20%20%20%20N%20--%3E%20O%5BSystem%20prompt%20citation%20rules%5D%0A%20%20%20%20%20%20%20%20O%20--%3E%20P%5BStream%20answer%20%2B%20position%20footnotes%5D%0A%20%20%20%20%20%20%20%20P%20--%3E%20Q%5BRender%20clickable%20footnotes%5D%0A%20%20%20%20%20%20%20%20Q%20--%3E%20R%5BClick%20%E2%86%92%20preview%20%E2%86%92%20jump%20%26%20highlight%5D%0A%20%20%20%20end",[10,913,914,915],{},"Core idea: ",[117,916,917],{},"do not let the model “answer from memory”—make it “gather evidence, then answer, and mark sources.”",[24,919],{},[27,921,923],{"id":922},"iv-preprocessing-turn-the-whole-book-into-a-searchable-segment-index","IV. Preprocessing: Turn the whole book into a searchable segment index",[10,925,926,927,930,931,934,935,938,939,942,943,946],{},"If every question still used ",[117,928,929],{},"stage 1"," full-book context, long books blow token budgets and retrieval is too coarse. Stage 3: on first AI chat for a book, run a ",[117,932,933],{},"segment summary job"," in the background—split by ",[117,936,937],{},"TOC"," or ",[117,940,941],{},"text length"," into ",[99,944,945],{},"Segment","s, summarize each, persist in local IndexedDB.",[10,948,949,950,952,953,956],{},"Each ",[99,951,945],{}," holds summary plus ",[117,954,955],{},"physical position in the body",":",[702,958,959,969],{},[705,960,961],{},[708,962,963,966],{},[711,964,965],{},"Field",[711,967,968],{},"Meaning",[724,970,971,984,997,1007],{},[708,972,973,981],{},[729,974,975,102,978],{},[99,976,977],{},"startFileIndex",[99,979,980],{},"endFileIndex",[729,982,983],{},"Spine file index (PDF: one file per page)",[708,985,986,994],{},[729,987,988,102,991],{},[99,989,990],{},"startOffset",[99,992,993],{},"endOffset",[729,995,996],{},"Character start/end",[708,998,999,1004],{},[729,1000,1001],{},[99,1002,1003],{},"sequence",[729,1005,1006],{},"Linear reading order",[708,1008,1009,1014],{},[729,1010,1011],{},[99,1012,1013],{},"title",[729,1015,1016],{},"TOC title",[10,1018,1019],{},"Splitting balances precision and cost: if a TOC node’s body is under ~20KB, summarize that node only; sibling nodes may merge into batches (15–20KB) before LLM calls; unstructured long blocks split in ~30–40k character ranges.",[10,1021,1022,1023,1026,1027,1030],{},"The summary system prompt requires ",[117,1024,1025],{},"keeping inline position tags"," (",[99,1028,1029],{},"[fNumber-Number-Number]",") so Tool-fetched source aligns with spine offsets. Core constraint:",[1032,1033,1038],"pre",{"className":1034,"code":1036,"language":1037,"meta":72},[1035],"language-text","If summary content relates to a passage, keep the trailing position tag [fNumber-Number-Number] (e.g. [f1-90-109]).\nTags are atomic—do not alter, merge, or omit any character or digit.\n","text",[99,1039,1036],{"__ignoreMap":72},[10,1041,1042,1043,1046],{},"After preprocessing, Q&A depends on a ",[117,1044,1045],{},"structured segment index",", not whole-book context—the engineering prerequisite for zero hallucination on long books.",[24,1048],{},[27,1050,1052],{"id":1051},"v-position-tag-system-encode-where-into-text","V. Position tag system: Encode “where” into text",[10,1054,1055,1056,1059,1060,1063],{},"Zero hallucination requires content from source ",[117,1057,1058],{},"and"," machine-parseable, UI-jumpable ",[117,1061,1062],{},"provenance",". We use inline tags:",[1032,1065,1068],{"className":1066,"code":1067,"language":1037},[1035],"[f{fileIndex}-{startChar}-{endChar}]\n",[99,1069,1067],{"__ignoreMap":72},[10,1071,1072,1073,1076],{},"Example: ",[99,1074,1075],{},"[f5-123-165]"," = spine file 5 (0-based), characters 123–165.",[61,1078,1080],{"id":1079},"_51-how-tags-are-written-into-body-text","5.1 How tags are written into body text",[10,1082,1083,1084,1087],{},"The extraction layer appends ",[99,1085,1086],{},"[f{fileIndex}-{start}-{end}]"," at segment ends:",[1032,1089,1094],{"className":1090,"code":1092,"language":1093,"meta":72},[1091],"language-typescript","const position = `[f${fileIndex}-${absOffset}-${absOffset + segment.length}]`;\nfileLines.push(segment.text.trim() + position);\n","typescript",[99,1095,1092],{"__ignoreMap":72},[10,1097,1098,1099,1102],{},"Whether preprocessing summaries or Tool excerpts, positions align with ",[117,1100,1101],{},"spine character offsets","—not model-guessed page numbers.",[61,1104,1106],{"id":1105},"_52-constraints-on-model-output","5.2 Constraints on model output",[10,1108,1109,1110,1116],{},"The system prompt includes ",[117,1111,1112],{},[1113,1114,1115],"span",{},"Position Citation Rules","—five core points:",[672,1118,1119,1129,1139,1145,1154],{},[38,1120,1121,1124,1125,1128],{},[117,1122,1123],{},"Standard format:"," Must use ",[99,1126,1127],{},"[f_fileIndex-startChar-endChar]","; all three numeric parts required;",[38,1130,1131,1134,1135,1138],{},[117,1132,1133],{},"Copy only from current sources:"," Footnotes must be ",[117,1136,1137],{},"verbatim"," from this turn’s system/user messages or Tool returns;",[38,1140,1141,1144],{},[117,1142,1143],{},"No fabrication:"," Do not compute, edit, or invent positions;",[38,1146,1147,1150,1151,627],{},[117,1148,1149],{},"Prefer omission:"," If no valid tag exists in context, answer normally—",[117,1152,1153],{},"output no position tags",[38,1155,1156,1159],{},[117,1157,1158],{},"Inline with claims:"," Tags follow the relevant sentence; no citation dumps at the end.",[10,1161,1162,1163,1166,1167,1170],{},"The UI also filters occasional ",[117,1164,1165],{},"two-part"," invalid tags (e.g. ",[99,1168,1169],{},"[f1-293]",") before render.",[10,1172,1173],{},[13,1174],{"alt":1175,"src":1176},"Citation trace popup","https://cdn.linghuxiong.com/resources/snapshots/ai-chat.png",[24,1178],{},[27,1180,1182],{"id":1181},"vi-tool-calling-retrieve-first-answer-second","VI. Tool Calling: Retrieve first, answer second",[10,1184,1185,1186,1189,1190,1193,1194,653],{},"When chat is bound to a book (",[99,1187,1188],{},"resourceId"," present, ",[99,1191,1192],{},"chatType === 'chat'","), we register two Tools with executors before each generation—standard OpenAI-style ",[117,1195,1196],{},"function calling loop",[61,1198,1200,1201,1204],{"id":1199},"_61-get_related_segment_summaries-targeted-segment-lookup","6.1 ",[99,1202,1203],{},"get_related_segment_summaries"," — Targeted segment lookup",[10,1206,1207,1208,653],{},"For: concepts, characters, plot, chapter details—",[117,1209,1210],{},"clear retrieval intent",[10,1212,1213],{},"Flow:",[672,1215,1216,1223,1229,1232,1242],{},[38,1217,1218,1219,1222],{},"Model rewrites user wording into ",[117,1220,1221],{},"terms likely to appear in the book"," (“Optimize Search Queries” in system prompt);",[38,1224,1225,1226,627],{},"Call Tool with ",[99,1227,1228],{},"question",[38,1230,1231],{},"Batch all segment summaries by token budget (~30k tokens per batch, max 5 batches);",[38,1233,1234,1235,1238,1239,627],{},"Each batch: separate LLM request picks relevant segment IDs (max 5) from ",[99,1236,1237],{},"{ id, title, summary }",", JSON like ",[99,1240,1241],{},"{\"Thinking\":\"...\",\"answer\":[\"1\",\"3\"]}",[38,1243,1244,1245,1248],{},"For selected segments, pull ",[117,1246,1247],{},"tagged source text"," from spine—not summaries—as Tool result.",[10,1250,1251,1254,1255,1258],{},[117,1252,1253],{},"Key design: Tool returns source, not summaries."," The model answers from real paragraphs with inline ",[99,1256,1257],{},"[f…]",", avoiding “summary → re-summary” drift.",[61,1260,1262,1263,1266],{"id":1261},"_62-get_full_book_segment_summaries-whole-book-overview","6.2 ",[99,1264,1265],{},"get_full_book_segment_summaries"," — Whole-book overview",[10,1268,1269,1270,653],{},"For: “summarize the book,” “review this book,” “overall structure/themes”—",[117,1271,1272],{},"global view",[10,1274,1275,1276,1279],{},"Concatenate all segment ",[99,1277,1278],{},"summary"," fields in reading order—avoid missing key chapters via per-chunk relevance only.",[61,1281,1283],{"id":1282},"_63-system-prompt-book-first-tools-first","6.3 System prompt: Book first, tools first",[10,1285,1286,1287,1292],{},"With a bound book, ",[117,1288,1289],{},[1113,1290,1291],{},"Core Principles for Reading Assistant"," applies:",[1032,1294,1297],{"className":1295,"code":1296,"language":1037},[1035],"1. Book First, Tool First\n   - Any question possibly about the book must call tools first;\n   - Answers must rely mainly on retrieval—never invent “book content” without retrieval.\n\n2. General Knowledge as Fallback Only\n   - Only for: casual chat / user explicitly skips the book / tools return nothing;\n   - If the book lacks it, say “not mentioned in this book” before general knowledge.\n\n3. Direct Style\n   - Get to the point—avoid “based on the provided materials…” and similar filler.\n",[99,1298,1296],{"__ignoreMap":72},[10,1300,1301,1302,1305,1306,1309],{},"Generation runs the tool loop: ",[99,1303,1304],{},"tool_calls"," → execute → append ",[99,1307,1308],{},"role: tool"," → continue until final text. With tools enabled, thinking channel is off to avoid protocol conflicts.",[24,1311],{},[27,1313,1315],{"id":1314},"vii-frontend-traceability-from-footnote-to-highlight","VII. Frontend traceability: From footnote to highlight",[10,1317,1318,1319,1321],{},"Model output ",[99,1320,1075],{}," is not shown raw; render layer turns it into clickable citations.",[61,1323,1325],{"id":1324},"_71-footnote-rendering","7.1 Footnote rendering",[10,1327,1328,1329,1332],{},"Normalize tags to Markdown links like ",[99,1330,1331],{},"[1]([f5-123-165])",", render as numbered footnotes; dedupe same position to avoid UI clutter.",[61,1334,1336],{"id":1335},"_72-click-interaction","7.2 Click interaction",[672,1338,1339,1348,1354],{},[38,1340,1341,1344,1345,1347],{},[117,1342,1343],{},"First click:"," Parse ",[99,1346,1257],{}," → fileIndex + offsets → extract spine text → preview (optional TOC title);",[38,1349,1350,1353],{},[117,1351,1352],{},"Same footnote again:"," Close preview;",[38,1355,1356,1359],{},[117,1357,1358],{},"Confirm jump:"," Open reader view, highlight character range.",[10,1361,1362,1363,1366],{},"From copied model tag to user-visible source, the chain ",[117,1364,1365],{},"never passes through another LLM call","—deterministic and reproducible.",[24,1368],{},[27,1370,1372],{"id":1371},"viii-edge-cases-and-honest-degradation","VIII. Edge cases and honest degradation",[10,1374,1375,1376,956],{},"Zero hallucination ≠ “always has an answer”—it means ",[117,1377,1378],{},"no evidence, no fabrication",[702,1380,1381,1391],{},[705,1382,1383],{},[708,1384,1385,1388],{},[711,1386,1387],{},"Scenario",[711,1389,1390],{},"Behavior",[724,1392,1393,1401,1413,1421,1429],{},[708,1394,1395,1398],{},[729,1396,1397],{},"Segment summaries not ready",[729,1399,1400],{},"Extract full text and summarize first",[708,1402,1403,1406],{},[729,1404,1405],{},"Tool finds nothing",[729,1407,1408,1409,1412],{},"Return ",[99,1410,1411],{},"(No relevant segment excerpts found…)","; model should say not in book",[708,1414,1415,1418],{},[729,1416,1417],{},"Invalid two-part tags from model",[729,1419,1420],{},"Frontend filters; no broken footnotes",[708,1422,1423,1426],{},[729,1424,1425],{},"Casual chat",[729,1427,1428],{},"System prompt allows general knowledge off-book",[708,1430,1431,1434],{},[729,1432,1433],{},"Export chat",[729,1435,1436],{},"Footnotes can become reader deep links for sharing/archiving",[10,1438,1439],{},[13,1440],{"alt":1441,"src":1442},"Chat export","https://cdn.linghuxiong.com/resources/snapshots/ai-chat-export.png",[24,1444],{},[27,1446,1448],{"id":1447},"ix-design-trade-off-why-not-vector-rag","IX. Design trade-off: Why not “vector RAG”?",[10,1450,1451,1452,1455],{},"Peers building document Q&A often ask: if you do retrieval-augmented generation, why not ",[117,1453,1454],{},"Embedding + vector DB Top-K","?",[10,1457,1458,1459,1462,1463,1466,1467,1470,1471,1474],{},"We ",[117,1460,1461],{},"are doing RAG","—retrieve before generate. The difference: “RAG” in community speech often implies ",[117,1464,1465],{},"vector similarity","; our stage 3 is ",[117,1468,1469],{},"segment index + Tool on-demand source pull","—",[117,1472,1473],{},"no vector layer by design",". Below: architectural reasons, not denying vector RAG’s value.",[61,1476,1478],{"id":1477},"scope-not-no-retrieval-but-no-vector-retrieval","Scope: not “no retrieval,” but “no vector retrieval”",[35,1480,1481,1490],{},[38,1482,1483,1486,1487,627],{},[117,1484,1485],{},"Broad RAG:"," retrieve → generate → ",[117,1488,1489],{},"we do this",[38,1491,1492,1495,1496,653],{},[117,1493,1494],{},"Vector RAG:"," recall via embedding similarity → ",[117,1497,1498],{},"not in this version",[10,1500,1501,1502,1505,1506,1509],{},"Preprocessing builds a ",[117,1503,1504],{},"segment summary index","; the model picks segments via Tools and gets ",[117,1507,1508],{},"source text",". Retrieval exists without a separate embedding model and vector index upkeep.",[24,1511],{},[61,1513,1515],{"id":1514},"reason-1-custom-llm-providerskeep-the-integration-surface-small","Reason 1: Custom LLM providers—keep the integration surface small",[10,1517,1518,1519,1522,1523,1526],{},"Users can plug ",[117,1520,1521],{},"their own API keys",", custom base URLs, or ",[117,1524,1525],{},"local Ollama","—chat model is their choice; cost and data path stay under control.",[10,1528,1529],{},"Typical vector RAG widens integration:",[35,1531,1532,1543,1546],{},[38,1533,1534,1535,1538,1539,1542],{},"Besides ",[117,1536,1537],{},"chat model",", you usually need an ",[117,1540,1541],{},"embedding model"," (another name, sometimes another endpoint);",[38,1544,1545],{},"Local Ollama needs a separate embedding model plus dimension/API compatibility;",[38,1547,1548,1549,1552],{},"More failure modes: chat works but ",[117,1550,1551],{},"empty retrieval","—embedding, index, or dimension mismatch; harder to debug than one provider end-to-end.",[10,1554,1555,1556,1559,1560,1563],{},"Here, ",[117,1557,1558],{},"segment picking and answering share one provider config","—no “chat on A, index on B.” For ",[117,1561,1562],{},"pluggable LLM"," apps, that often beats a few points of recall.",[10,1565,1566],{},[13,1567],{"alt":1568,"src":1569},"Custom AI providers","https://cdn.linghuxiong.com/resources/snapshots/ai-customize-providers.png",[24,1571],{},[61,1573,1575],{"id":1574},"reason-2-embeddings-bind-to-the-indexprovider-switches-are-expensive","Reason 2: Embeddings bind to the index—provider switches are expensive",[10,1577,1578,1579,1582,1583,1586,1587,1590],{},"In vector RAG, ",[117,1580,1581],{},"vectors are not a universal intermediate format","—they are coordinates under one embedding model. Index with A, query with B: similarity is usually ",[117,1584,1585],{},"not comparable","—often ",[117,1588,1589],{},"full re-embedding",", and dimensions (768 / 1024 / 1536 …) lock storage schema.",[10,1592,1593,1594,1597,1598,1601],{},"Stage 3 persists ",[117,1595,1596],{},"structured summaries + character spans",", not vectors; switching chat models ",[117,1599,1600],{},"does not rebuild the index","; evidence chain (source positions) stays the same—aligned with “try different LLMs anytime.”",[24,1603],{},[61,1605,1607],{"id":1606},"reason-3-structured-routing-is-often-enough-for-toc-heavy-long-docs","Reason 3: Structured routing is often enough for TOC-heavy long docs",[10,1609,1610,1611,1614,1615,1618,1619,1622,1623,1628],{},"E-books and PDFs usually have ",[117,1612,1613],{},"chapter structure","; preprocessing yields ",[117,1616,1617],{},"segment titles + summaries",". For “what does chapter X say” or “how does the book define Y,” pick segments from the catalog then ",[117,1620,1621],{},"pull source"," works well in practice; Tool returns ",[117,1624,1625,1626],{},"source with ",[99,1627,1257],{},", so zero hallucination stays anchored on character spans.",[10,1630,1631,1632,1635,1636,1639],{},"Vectors help fuzzy semantics, cross-language, long-span literal mismatch; for ",[117,1633,1634],{},"TOC + preprocess + strong traceability"," readers, investing in ",[117,1637,1638],{},"Tool + source return + citation rules"," often has better ROI.",[24,1641],{},[61,1643,1645],{"id":1644},"future-hybrid-recall-not-a-rewrite","Future: Hybrid recall, not a rewrite",[10,1647,1648,1649,1652,1653,1656,1657,1660,1661,1664],{},"We may add ",[117,1650,1651],{},"vector coarse recall"," (embedding only for Top-N chapter candidates), still ending in ",[117,1654,1655],{},"pick segment → source → clickable trace","—zero-hallucination rules unchanged. If added: embedding ",[117,1658,1659],{},"optional",", explicit ",[117,1662,1663],{},"re-index"," prompts when models change—avoid silent wrong retrieval.",[10,1666,1667,1668],{},"Until then: ",[117,1669,1670],{},"any OpenAI-compatible chat API works; changing chat model does not rebuild local index.",[24,1672],{},[27,1674,1676],{"id":1675},"x-summary","X. Summary",[702,1678,1679,1692],{},[705,1680,1681],{},[708,1682,1683,1686,1689],{},[711,1684,1685],{},"Step",[711,1687,1688],{},"Method",[711,1690,1691],{},"Role",[724,1693,1694,1705,1718,1731,1742,1753],{},[708,1695,1696,1699,1702],{},[729,1697,1698],{},"Preprocess",[729,1700,1701],{},"Split by TOC/length + segment summary cache",[729,1703,1704],{},"Long books searchable & locatable",[708,1706,1707,1710,1715],{},[729,1708,1709],{},"Position tags",[729,1711,1712,1714],{},[99,1713,577],{}," in source",[729,1716,1717],{},"Machine-parseable provenance",[708,1719,1720,1723,1728],{},[729,1721,1722],{},"Tool retrieval",[729,1724,1725,1726],{},"Per-question segments / full-book summaries, return ",[117,1727,743],{},[729,1729,1730],{},"Force evidence before answer",[708,1732,1733,1736,1739],{},[729,1734,1735],{},"System prompt",[729,1737,1738],{},"Book first, no fake tags, say when missing",[729,1740,1741],{},"Constrain generation",[708,1743,1744,1747,1750],{},[729,1745,1746],{},"Frontend",[729,1748,1749],{},"Footnote → preview → jump & highlight",[729,1751,1752],{},"User verifies evidence",[708,1754,1755,1758,1761],{},[729,1756,1757],{},"No vector retrieval",[729,1759,1760],{},"Single provider; swap chat model without re-index",[729,1762,1763],{},"Lower integration & migration cost",[10,1765,1766,1767,1770],{},"“Zero hallucination” does not mean the model never errs—it means ",[117,1768,1769],{},"engineering locks output to an evidence chain",": no retrieval → do not pose as book content; with retrieval → give verifiable source positions.",[10,1772,1773,1774,1777,1778,1781],{},"If you build AI reading or document Q&A, we hope the path ",[117,1775,1776],{},"full dump → key sentences → Tool-first on-demand retrieval",", plus ",[117,1779,1780],{},"inline position tags + source return",", is a useful reference implementation.",[18,1783,1784],{},[10,1785,1786,1787,1791,1792,653],{},"These are lessons from building ",[664,1788,267],{"href":1789,"rel":1790},"https://reader.linghuxiong.com",[668]," AI reader—for reference only. Try the reader on the ",[664,1793,1795],{"href":1794},"/en#download","download page",{"title":72,"searchDepth":238,"depth":238,"links":1797},[1798,1803,1804,1805,1806,1810,1817,1821,1822,1829],{"id":464,"depth":238,"text":465,"children":1799},[1800,1801,1802],{"id":480,"depth":244,"text":481},{"id":560,"depth":244,"text":561},{"id":656,"depth":244,"text":657},{"id":846,"depth":238,"text":847},{"id":907,"depth":238,"text":908},{"id":922,"depth":238,"text":923},{"id":1051,"depth":238,"text":1052,"children":1807},[1808,1809],{"id":1079,"depth":244,"text":1080},{"id":1105,"depth":244,"text":1106},{"id":1181,"depth":238,"text":1182,"children":1811},[1812,1814,1816],{"id":1199,"depth":244,"text":1813},"6.1 get_related_segment_summaries — Targeted segment lookup",{"id":1261,"depth":244,"text":1815},"6.2 get_full_book_segment_summaries — Whole-book overview",{"id":1282,"depth":244,"text":1283},{"id":1314,"depth":238,"text":1315,"children":1818},[1819,1820],{"id":1324,"depth":244,"text":1325},{"id":1335,"depth":244,"text":1336},{"id":1371,"depth":238,"text":1372},{"id":1447,"depth":238,"text":1448,"children":1823},[1824,1825,1826,1827,1828],{"id":1477,"depth":244,"text":1478},{"id":1514,"depth":244,"text":1515},{"id":1574,"depth":244,"text":1575},{"id":1606,"depth":244,"text":1607},{"id":1644,"depth":244,"text":1645},{"id":1675,"depth":238,"text":1676},"2026-06-03","Engineering notes on zero-hallucination Q&A in an AI reader—answers grounded in the current book, with one-click citations back to exact passages.",{},"/en/blog/zero-hallucination-qa",{"title":438,"description":1831},"en/blog/zero-hallucination-qa",[1837,1838,1839],"reader","AI","engineering","zero-hallucination-qa","uvw654rlcM4E60wP4tYzIynEFr2kFaRn6sdNW-J_HhI",1786513819765]