LLM-wiki Ingest flow: A.md / B.md ์ถ์ ์์
๋ชฉํ: A.md, B.md ๋ ๋ฌธ์๋ฅผ ingest ํ์ ๋ ์๋ณธ chunk โ LLM claim โ wiki/claims.json โ wiki/concepts/Matcher.md๊น์ง ์ด๋ค ID๋ก ์ฐ๊ฒฐ๋๋์ง ํ ๋ฒ์ ์ถ์ ํ๋ค.
์ ์ :
- ์์๋ ์ฝ๋ ๊ท์น์ ๋ง์ถ ์ถ์ ์ฉ ์ํ์ด๋ค.
- LLM ์๋ต ๋ด์ฉ์ ์คํ๋ง๋ค ๋ฌ๋ผ์ง ์ ์์ง๋ง, ID ์์ฑ/๋ณด์กด/๊ทธ๋ฃนํ ๊ท์น์ ์ฝ๋ ๋ก์ง์ ๋ฐ๋ฅธ๋ค.
- ์๋ ์์๋
A.md์์๋summary=c1,Matcher concept=c2๊ฐ ์์ฑ๋๊ณ ,B.md์์๋summary=c1,Tool concept=c2,Matcher concept=c3๊ฐ ์์ฑ๋ ์ํฉ์ ๊ธฐ์ค์ผ๋ก ํ๋ค.
0. ํต์ฌ ๊ฒฐ๋ก
flowchart LR A["A.md<br/>sourcePath=A.md<br/>sourceId=src:2d63174e212b2fdb"] --> AC["source chunk<br/>ordinal 0/1<br/>stableChunkId"] B["B.md<br/>sourcePath=B.md<br/>sourceId=src:b5038c9fd9be6c6f"] --> BC["source chunk<br/>ordinal 0/1<br/>stableChunkId"] AC --> AE["evidence<br/>src:2d63174e212b2fdb:e2<br/>A.md lines 2-2"] BC --> BE["evidence<br/>src:b5038c9fd9be6c6f:e3<br/>B.md lines 4-4"] AE --> AK["claimKey<br/>src:2d63174e212b2fdb:c2<br/>subject=Matcher"] BE --> BK["claimKey<br/>src:b5038c9fd9be6c6f:c3<br/>subject=Matcher"] AK --> REG["wiki/claims.json<br/>claim์ source-aware๋ก ๋ณ๋ ๋ณด์กด"] BK --> REG REG --> GROUP["step8 concept grouping<br/>key=lowercase(trim(NFC(subject)))<br/>matcher"] GROUP --> WIKI["wiki/concepts/Matcher.md<br/>A.md ์น์ + B.md ์น์ "]
ํต์ฌ:
claims.json์์๋ A/B claim์ dedupeํ์ง ์๋๋ค.claimKey๋sourcePath + claimId๊ธฐ๋ฐ์ด๋ผ A.md์Matcher์ B.md์Matcher๋ ์๋ก ๋ค๋ฅธ claim์ด๋ค.- concept wiki ๋จ๊ณ์์๋ง
subject์ ๊ทํ๊ฐ์ด ๊ฐ์ claim๋ค์ ํ ํ์ด์ง์ ๋ชจ์ ๋ณด์ฌ์ค๋ค.
1. ์์ ์ ๋ ฅ
A.md
# A
Matcher๋ ์์ฒญ ์กฐ๊ฑด์ ํ๊ฐํด ๋์ ์ฌ๋ถ๋ฅผ ๊ฒฐ์ ํ๋ค.
## Detail
Matcher๋ ๋ผ์ฐํ
์ ์ ์
๋ ฅ ํจํด์ ๊ฒ์ฌํ๋ค.B.md
# B
Tool ํธ์ถ์ ์ ์ฑ
๊ฒ์ฌ๋ฅผ ๋จผ์ ํต๊ณผํด์ผ ํ๋ค.
## Matcher
Matcher๋ ๋๊ตฌ ํธ์ถ ๊ฐ๋ฅ ์ฌ๋ถ๋ฅผ ํ๋จํ๋ ๊ท์น ์งํฉ์ด๋ค.2. ๋จ๊ณ๋ณ ์ ์ฒด ํ๋ฆ
sequenceDiagram participant SRC as Source files participant S1 as step1 Discover/Classify participant S2 as step2 Parse/Chunk participant S4 as step4 LLM Generate participant S5 as step5 Validate participant S6 as step6 Backup/Write participant S7 as step7 Merge Claims participant S8 as step8 Sync Concept Wiki SRC->>S1: A.md, B.md scan S1->>S2: changed source documents S2->>S4: chunks + raw source S4->>S5: generated wiki page + SourceClaim[] S5->>S6: validated claims and markdown S6->>S7: claimUpdates + generated wiki page checkpoint S7->>S7: mergeSourceClaims(existing, updates, currentSourcePaths) S7->>S8: wiki/claims.json S8->>S8: concept claims grouped by normalized subject S8->>SRC: wiki/concepts/Matcher.md
์ฃผ์: backend์๋ step3 Queue Wiki work๊ฐ ์์ง๋ง visualizer์ ๋ฌธ์/์คํ ํ๋ฆ์์๋ ๋ด๋ถ ํ ๋จ๊ณ๋ผ ํต์ฌ ์ค๋ช
์์ ์๋ตํ๋ค.
3. Step 1: source ์๋ณ
sourceId๋ sourcePath๋ง์ผ๋ก ๋ง๋ ๋ค.
sourceId = "src:" + sha256(normalizedSourcePath).slice(0, 16)
claimKey = `${sourceId}:${claimId}`
evidenceId = `${sourceId}:e${n}`| file | sourcePath | sourceId |
|---|---|---|
| A.md | A.md | src:2d63174e212b2fdb |
| B.md | B.md | src:b5038c9fd9be6c6f |
sourceHash๋ ํ์ผ ๋ด์ฉ sha256์ด๋ค. ๊ฐ์ path๋ผ๋ ๋ด์ฉ์ด ๋ฐ๋๋ฉด sourceHash๊ฐ ๋ฐ๋๊ณ , ๋ณ๊ฒฝ ๋ฌธ์์ claim์ ์ claim์ผ๋ก ๊ต์ฒด๋๋ค.
| file | sourceHash |
|---|---|
| A.md | f0cc8c7b6269d5a4094467448e032b8d05c10bc4bee9a5525b7102ecc40e7695 |
| B.md | 5fddc130a5be77b2b79abe79f96d37cfd925511c276e34b3a0b80883c2b970c0 |
4. Step 2: chunk ๋ถํ
Markdown chunk๋ heading ๊ธฐ์ค์ผ๋ก ๋๋๋ค. visualizer payload์๋ ordinal, heading, lineStart, lineEnd๊ฐ ๋
ธ์ถ๋๋ค.
DB์๋ stableChunkId(sourcePath, sourceHash, ordinal, heading)๊ฐ ์ ์ฅ๋๋ค.
flowchart TD A["A.md"] --> A0["chunk A#0<br/>heading=A<br/>lines 1-2<br/>stableChunkId=9ecb66ee7cd861b4580c3014"] A --> A1["chunk A#1<br/>heading=A > Detail<br/>lines 3-4<br/>stableChunkId=211e2203d68696ce4a1c8241"] B["B.md"] --> B0["chunk B#0<br/>heading=B<br/>lines 1-2<br/>stableChunkId=cdc1d32699ceb97f6c595e53"] B --> B1["chunk B#1<br/>heading=B > Matcher<br/>lines 3-4<br/>stableChunkId=81527e658148f0b10efd8066"]
| sourcePath | visual chunk key | DB stableChunkId | heading | lines |
|---|---|---|---|---|
| A.md | A.md#0 | 9ecb66ee7cd861b4580c3014 | A | 1-2 |
| A.md | A.md#1 | 211e2203d68696ce4a1c8241 | A > Detail | 3-4 |
| B.md | B.md#0 | cdc1d32699ceb97f6c595e53 | B | 1-2 |
| B.md | B.md#1 | 81527e658148f0b10efd8066 | B > Matcher | 3-4 |
5. Step 4~5: LLM claim ์์ฑ๊ณผ ๊ฒ์ฆ
LLM์ ์๋ฌธ์์ summary/concept/relationship์ ๋ง๋ค๊ณ , ๊ฒ์ฆ ๋จ๊ณ์์ ๊ฐ claim์ ์๋ฌธ evidence range๊ฐ ๋ถ๋๋ค.
์์์์๋ A.md์ Matcher concept claim์ c2, B.md์ Matcher concept claim์ c3๋ก ๋ง๋ค์ด์ก๋ค๊ณ ๊ฐ์ ํ๋ค.
claimId๋ ๋ฌธ์๋ณ local ์๋ฒ์ด๋ค. ๊ฐ์ ๊ฐ๋
์ด๋ผ๋ ๋ฌธ์ ์์์ ๋ช ๋ฒ์งธ summary/concept/relationship์ผ๋ก ๋ง๋ค์ด์ก๋์ง์ ๋ฐ๋ผ c2, c3์ฒ๋ผ ๋ฌ๋ผ์ง ์ ์๋ค. evidence[0].lineStart-lineEnd๋ ์๋ฌธ ์ค ๋ฒํธ๋ผ ์ฐ์ฐํ ๊ฐ์ ์๋ ์๊ณ , ์๋์ฒ๋ผ ๋ค๋ฅผ ์๋ ์๋ค.
flowchart LR A0["A.md chunk #0<br/>lines 1-2"] --> AE2["evidence<br/>id=src:2d63174e212b2fdb:e2<br/>sourcePath=A.md<br/>lines 2-2"] AE2 --> AC2["claim<br/>claimId=c2<br/>claimKey=src:2d63174e212b2fdb:c2<br/>kind=concept<br/>subject=Matcher"] B1["B.md chunk #1<br/>lines 3-4"] --> BE3["evidence<br/>id=src:b5038c9fd9be6c6f:e3<br/>sourcePath=B.md<br/>lines 4-4"] BE3 --> BC3["claim<br/>claimId=c3<br/>claimKey=src:b5038c9fd9be6c6f:c3<br/>kind=concept<br/>subject=Matcher"]
์ค์ํ ์ฐ๊ฒฐ ๊ท์น:
| field | A.md Matcher claim | B.md Matcher claim |
|---|---|---|
claimId | c2 | c3 |
claimKey | src:2d63174e212b2fdb:c2 | src:b5038c9fd9be6c6f:c3 |
kind | concept | concept |
subject | Matcher | Matcher |
sourcePath | A.md | B.md |
sourceHash | A.md content hash | B.md content hash |
evidenceIds[0] | src:2d63174e212b2fdb:e2 | src:b5038c9fd9be6c6f:e3 |
evidence[0].sourcePath | A.md | B.md |
evidence[0].lineStart-lineEnd | 2-2 | 4-4 |
์ฌ๊ธฐ์ ์ค์ํ ๊ฒ์ claimId๊ฐ ์๋๋ผ claimKey๋ค. claimKey๋ sourcePath ๊ธฐ๋ฐ sourceId๋ฅผ ํฌํจํ๋ฏ๋ก source-aware claim identity๊ฐ ๋๋ค.
6. Step 6: generated wiki page ์ ์ฅ
๊ฐ source ๋ฌธ์๋ ์๊ธฐ ์์ generated wiki page๋ฅผ ๊ฐ์ง๋ค.
flowchart LR A["A.md"] --> AW["wiki/generated/A.wiki.md<br/>sourcePath=A.md<br/>sourceHash=A hash"] B["B.md"] --> BW["wiki/generated/B.wiki.md<br/>sourcePath=B.md<br/>sourceHash=B hash"] AW --> AWC["wiki page chunks<br/>ordinal/heading/lines"] BW --> BWC["wiki page chunks<br/>ordinal/heading/lines"]
์ด ๋จ๊ณ๋ claim dedupe ๋จ๊ณ๊ฐ ์๋๋ค.
ํ๋ ์ผ:
- ๊ธฐ์กด generated wiki page ๋ฐฑ์
- ์ markdown atomic write
- generated wiki page chunk๋ฅผ DB์ upsert
claimUpdates.push(...page.claims)๋ก ์ดํ registry merge์ ๋๊น
ํต์ฌ ์์ฝ: A.wiki.md๋ A.md๋ฅผ LLM/๊ฒ์/์ฌ๋์ด ์ฝ๊ธฐ ์ข์ wiki markdown์ผ๋ก ์ฌ์์ฑํ ํ์ผ์ด๋ค. claim ์ ์ฅ์๋ ์๋๋ฉฐ, ์ ๊ท claim ์ถ์ ์ wiki/claims.json์ด ๋ด๋นํ๋ค.
๊ฐ์ LLM ์๋ต์์ ๋ ์ข ๋ฅ์ ์ฐ์ถ๋ฌผ์ด ํจ๊ป ๋์จ๋ค๊ณ ๋ณด๋ฉด ๋๋ค.
flowchart LR LLM["step4 LLM response<br/>A.md ๋ถ์ ๊ฒฐ๊ณผ"] --> PAGE["page.markdown<br/>wiki/generated/A.wiki.md์ ์ ์ฅ"] LLM --> CLAIMS["page.claims<br/>step7 wiki/claims.json์ ๋ณํฉ"] PAGE --> INDEX["wiki_pages / wiki_chunks DB upsert"] CLAIMS --> REG["claimUpdates ๋ฐฐ์ด"]
์์ wiki/generated/A.wiki.md ํต์ฌ ํํ:
---
source_path: "A.md"
source_sha256: "f0cc8c7b6269d5a4094467448e032b8d05c10bc4bee9a5525b7102ecc40e7695"
aliases: ["Matcher"]
---
# A
Matcher๋ ์์ฒญ ์กฐ๊ฑด์ ํ๊ฐํด ๋์ ์ฌ๋ถ๋ฅผ ๊ฒฐ์ ํ๋ค.
## Matcher
Matcher๋ ์์ฒญ ์กฐ๊ฑด์ ํ๊ฐํด ๋์ ์ฌ๋ถ๋ฅผ ๊ฒฐ์ ํ๊ณ , ๋ผ์ฐํ
์ ์ ์
๋ ฅ ํจํด์ ๊ฒ์ฌํ๋ค.
## ์๋ฌธ ๊ทผ๊ฑฐ
- A.md:2-2 โ Matcher๋ ์์ฒญ ์กฐ๊ฑด์ ํ๊ฐํด ๋์ ์ฌ๋ถ๋ฅผ ๊ฒฐ์ ํ๋ค.
- A.md:4-4 โ Matcher๋ ๋ผ์ฐํ
์ ์ ์
๋ ฅ ํจํด์ ๊ฒ์ฌํ๋ค.์ด ํ์ผ์ ์ญํ :
- ๊ฒ์/์ฝ๊ธฐ์ฉ wiki page๋ค.
sourcePath=A.md,sourceHash=A hash๋ก A.md์ ์์ ๋๋ค.- page markdown์์ ๋ค์ chunk๊ฐ ๋ง๋ค์ด์ ธ
wiki_chunks์ ์ ์ฅ๋๋ค. - claim registry์ ์ ๊ท ์๋ณธ์ ์๋๋ค. ์ ๊ท claim ๋ชฉ๋ก์ ๋ค์ ๋จ๊ณ์
wiki/claims.json์ด๋ค.
7. Step 7: wiki/claims.json ํตํฉ
mergeSourceClaims(existing, updates, currentSourcePaths)๊ฐ ์คํ๋๋ค.
์์์ ์๋๋ก ์ฝ์ผ๋ฉด ๋๋ค. ๋จผ์ DB์ ์ ์ฅ๋ ๊ธฐ์กด source ๋ชฉ๋ก๊ณผ ํ์ฌ ๋์คํฌ scan ๊ฒฐ๊ณผ๋ฅผ ํฉ์ณ โํ์ฌ ์ด์์๋ source ๋ชฉ๋กโ์ ๋ง๋ ๋ค. ๊ทธ ๋ค์ ๊ธฐ์กด wiki/claims.json๊ณผ ์ด๋ฒ ์คํ์์ ์๋ก ์ถ์ถํ claim์ ๋น๊ตํ๋ค. ๋ง์ง๋ง์ผ๋ก ์ฌ๋ผ์ง source์ claim์ ์ ๊ฑฐํ๊ณ , ์ด๋ฒ์ ๋ค์ ์ฒ๋ฆฌ๋ source์ claim์ ์ claim์ผ๋ก ๊ต์ฒดํ๋ค.
A.new๋ A.md์ hash๊ฐ ๋ฐ๋์ด LLM์ด ๋ค์ ์์ฑํ ์ด๋ฒ ์คํ์ ์ claim์ ๋ปํ๋ค.
sequenceDiagram participant DB as DB ๊ธฐ์กด source ๋ชฉ๋ก participant Disk as ํ์ฌ ๋์คํฌ scan participant Current as ํ์ฌ source ๋ชฉ๋ก participant Prior as ๊ธฐ์กด claims.json participant Updates as ์ด๋ฒ ์คํ claim participant Merge as claim ํตํฉ ๋ก์ง participant Out as ์ต์ข claims.json DB->>Current: ๊ธฐ์กด์ ์๋ path๋ก ์์<br/>A.md, B.md, C.md Disk->>Current: ์ง๊ธ ๋ฐ๊ฒฌ๋ path ๋ฐ์<br/>A.md, B.md Current->>Current: ํ์ฌ source์ ์๋ path ์ ๊ฑฐ<br/>C.md ์ ๊ฑฐ Prior->>Merge: ๊ธฐ์กด claim ์ ๋ฌ<br/>A.old:c2, B.old:c3, C.old:c2 Updates->>Merge: ์ด๋ฒ์ ์๋ก ๊ฒ์ฆ๋ claim ์ ๋ฌ<br/>A.new:c2, B.new:c3 Current->>Merge: ํ์ฌ ์ ํจํ source ์ ๋ฌ<br/>A.md, B.md Merge->>Merge: ์ฌ๋ผ์ง source์ claim ์ ๊ฑฐ<br/>C.old:c2 ์ ๊ฑฐ Merge->>Merge: ๋ค์ ์ฒ๋ฆฌ๋ source์ ๊ธฐ์กด claim ์ ๊ฑฐ<br/>A.old:c2, B.old:c3 ์ ๊ฑฐ Merge->>Merge: ์ด๋ฒ ์คํ claim ์ถ๊ฐ<br/>A.new:c2, B.new:c3 ์ถ๊ฐ Merge->>Out: ์ต์ข registry ์ ์ฅ<br/>A.new:c2, B.new:c3
7-1. merge ์์ ์ wiki/claims.json
์๋๋ ์ด์ ์คํ ๊ฒฐ๊ณผ๊ฐ ๋จ์ ์๋ ์ํฉ์ด๋ค.
{
"version": 1,
"claims": [
{
"claimKey": "src:2d63174e212b2fdb:c2",
"subject": "Matcher",
"sourcePath": "A.md",
"statement": "OLD: A.md์ ์ด์ Matcher ์ค๋ช
"
},
{
"claimKey": "src:b5038c9fd9be6c6f:c3",
"subject": "Matcher",
"sourcePath": "B.md",
"statement": "OLD: B.md์ ์ด์ Matcher ์ค๋ช
"
},
{
"claimKey": "src:removedsource0000:c2",
"subject": "Removed Concept",
"sourcePath": "C.md",
"statement": "C.md๋ ์ด๋ฒ source set์ ์์"
}
]
}7-2. ์ด๋ฒ ์คํ ์ ๋ ฅ
{
"currentSourcePaths": ["A.md", "B.md"],
"updates": [
{
"claimKey": "src:2d63174e212b2fdb:c2",
"subject": "Matcher",
"sourcePath": "A.md",
"statement": "NEW: A.md์์ ์๋ก ๊ฒ์ฆ๋ Matcher ์ค๋ช
"
},
{
"claimKey": "src:b5038c9fd9be6c6f:c3",
"subject": "Matcher",
"sourcePath": "B.md",
"statement": "NEW: B.md์์ ์๋ก ๊ฒ์ฆ๋ Matcher ์ค๋ช
"
}
]
}7-3. mergeSourceClaims ๊ณผ์
// 1) currentSourcePaths์ ์๋ claim ์ ๊ฑฐ
// - C.md claim ์ ๊ฑฐ
// 2) ์ด๋ฒ updates์ ํฌํจ๋ source์ ๊ธฐ์กด claim ์ ๊ฑฐ
// - A.md old claim ์ ๊ฑฐ
// - B.md old claim ์ ๊ฑฐ
// 3) updates claim ์ถ๊ฐ
// - A.md new claim ์ถ๊ฐ
// - B.md new claim ์ถ๊ฐ
// 4) claimKey ๊ธฐ์ค Map์ผ๋ก ์ ๋ฆฌ ํ ์ ๋ ฌ7-4. merge ํ wiki/claims.json
์์ ์ต์ข
wiki/claims.json ํต์ฌ ํํ:
{
"version": 1,
"claims": [
{
"claimId": "c2",
"claimKey": "src:2d63174e212b2fdb:c2",
"kind": "concept",
"subject": "Matcher",
"statement": "Matcher๋ ์์ฒญ ์กฐ๊ฑด์ ํ๊ฐํด ๋์ ์ฌ๋ถ๋ฅผ ๊ฒฐ์ ํ๋ค.",
"sourcePath": "A.md",
"sourceHash": "f0cc8c7b6269d5a4094467448e032b8d05c10bc4bee9a5525b7102ecc40e7695",
"evidenceIds": ["src:2d63174e212b2fdb:e2"],
"evidence": [
{
"id": "src:2d63174e212b2fdb:e2",
"sourcePath": "A.md",
"sourceHash": "f0cc8c7b6269d5a4094467448e032b8d05c10bc4bee9a5525b7102ecc40e7695",
"lineStart": 2,
"lineEnd": 2,
"quote": "Matcher๋ ์์ฒญ ์กฐ๊ฑด์ ํ๊ฐํด ๋์ ์ฌ๋ถ๋ฅผ ๊ฒฐ์ ํ๋ค."
}
]
},
{
"claimId": "c3",
"claimKey": "src:b5038c9fd9be6c6f:c3",
"kind": "concept",
"subject": "Matcher",
"statement": "Matcher๋ ๋๊ตฌ ํธ์ถ ๊ฐ๋ฅ ์ฌ๋ถ๋ฅผ ํ๋จํ๋ ๊ท์น ์งํฉ์ด๋ค.",
"sourcePath": "B.md",
"sourceHash": "5fddc130a5be77b2b79abe79f96d37cfd925511c276e34b3a0b80883c2b970c0",
"evidenceIds": ["src:b5038c9fd9be6c6f:e3"],
"evidence": [
{
"id": "src:b5038c9fd9be6c6f:e3",
"sourcePath": "B.md",
"sourceHash": "5fddc130a5be77b2b79abe79f96d37cfd925511c276e34b3a0b80883c2b970c0",
"lineStart": 4,
"lineEnd": 4,
"quote": "Matcher๋ ๋๊ตฌ ํธ์ถ ๊ฐ๋ฅ ์ฌ๋ถ๋ฅผ ํ๋จํ๋ ๊ท์น ์งํฉ์ด๋ค."
}
]
}
]
}์๊ฐ์ ์ผ๋ก ๋ณด๋ฉด:
flowchart LR AC2["A.md Matcher claim<br/>src:2d63174e212b2fdb:c2"] --> REG["wiki/claims.json"] BC3["B.md Matcher claim<br/>src:b5038c9fd9be6c6f:c3"] --> REG REG --> KEEP["๋ claim ๋ชจ๋ ๋ณด์กด<br/>dedupe ์์"]
8. Step 8: concept wiki ์์ฑ
์ด ๋จ๊ณ์์ kind === "concept" claim๋ง ๋ชจ์๋ค.
๊ทธ๋ฃน ํค:
conceptGroupKey = claim.subject.normalize("NFC").trim().toLocaleLowerCase()์์์์๋ ๋ claim ๋ชจ๋ subject=Matcher์ด๋ฏ๋ก ๊ฐ์ ๊ทธ๋ฃน์ด ๋๋ค.
flowchart TD REG["wiki/claims.json"] --> FILTER["kind === concept"] FILTER --> ACLAIM["A.md<br/>subject=Matcher<br/>claimKey=src:2d63174e212b2fdb:c2"] FILTER --> BCLAIM["B.md<br/>subject=Matcher<br/>claimKey=src:b5038c9fd9be6c6f:c3"] ACLAIM --> GROUP["group key: matcher"] BCLAIM --> GROUP GROUP --> PAGE["wiki/concepts/Matcher.md"] PAGE --> SEC_A["section A.md<br/>A claim statement<br/>A evidence quote"] PAGE --> SEC_B["section B.md<br/>B claim statement<br/>B evidence quote"]
์์ wiki/concepts/Matcher.md ํต์ฌ ํํ:
---
concept: "Matcher"
claim_keys: ["src:2d63174e212b2fdb:c2", "src:b5038c9fd9be6c6f:c3"]
sources: ["A.md", "B.md"]
generated_at: "..."
---
# Matcher
## A.md
Matcher๋ ์์ฒญ ์กฐ๊ฑด์ ํ๊ฐํด ๋์ ์ฌ๋ถ๋ฅผ ๊ฒฐ์ ํ๋ค.
> [!quote] A.md:2-2
>
> Matcher๋ ์์ฒญ ์กฐ๊ฑด์ ํ๊ฐํด ๋์ ์ฌ๋ถ๋ฅผ ๊ฒฐ์ ํ๋ค.
## B.md
Matcher๋ ๋๊ตฌ ํธ์ถ ๊ฐ๋ฅ ์ฌ๋ถ๋ฅผ ํ๋จํ๋ ๊ท์น ์งํฉ์ด๋ค.
> [!quote] B.md:4-4
>
> Matcher๋ ๋๊ตฌ ํธ์ถ ๊ฐ๋ฅ ์ฌ๋ถ๋ฅผ ํ๋จํ๋ ๊ท์น ์งํฉ์ด๋ค.9. Dedupe๊ฐ ์๋๋ผ concept projection์ธ ์ด์
flowchart LR subgraph "dedupe๋ผ๋ฉด" DA["A.md Matcher claim"] --> D["ํ๋์ ํตํฉ claim"] DB["B.md Matcher claim"] --> D end subgraph "ํ์ฌ llm-wiki" CA["A.md Matcher claim<br/>claimKey A:c2"] --> R["wiki/claims.json<br/>claim 2๊ฐ ์ ์ง"] CB["B.md Matcher claim<br/>claimKey B:c3"] --> R R --> P["wiki/concepts/Matcher.md<br/>๊ฐ์ ํ์ด์ง์ source๋ณ ์น์ ์ผ๋ก ํ์"] end
| ๊ตฌ๋ถ | dedupe | ํ์ฌ concept wiki |
|---|---|---|
| claim ๊ฐ์ | ์ค์ด๋ ๋ค | ์ ์ง๋๋ค |
claimKey | ํ๋๋ก ํฉ์ณ์ง ์ ์๋ค | source-aware key ๊ทธ๋๋ก ์ ์ง |
| ์๋ณธ ์ถ์ | ์ฝํด์ง ์ ์๋ค | sourcePath/sourceHash/evidence line ์ ์ง |
| ๋ชฉ์ | ์ค๋ณต ์ ๊ฑฐ | ๊ฐ์ ๊ฐ๋ ์ claim๋ค์ ํ ํ์ด์ง์ ๋ชจ์ ๋ณด๊ธฐ |
10. ID ์ญ์ถ์ ๋ฐฉ๋ฒ
wiki/concepts/Matcher.md์์ ์๋ณธ์ผ๋ก ๋์๊ฐ๋ ๊ฒฝ๋ก:
flowchart RL PAGE["wiki/concepts/Matcher.md"] --> FK["frontmatter claim_keys"] FK --> CK["claimKey<br/>src:2d63174e212b2fdb:c2"] CK --> REG["wiki/claims.json์์ claim lookup"] REG --> SP["sourcePath=A.md"] REG --> SH["sourceHash=A hash"] REG --> EV["evidenceId=src:2d63174e212b2fdb:e2<br/>lineStart=2<br/>lineEnd=2"] EV --> SRC["A.md ์๋ฌธ 2๋ฒ์งธ ์ค"]
์ฒดํฌ๋ฆฌ์คํธ:
- concept wiki frontmatter์
claim_keys๋ฅผ ํ์ธํ๋ค. - ๊ฐ์
claimKey๋ฅผwiki/claims.json์์ ์ฐพ๋๋ค. - ํด๋น claim์
sourcePath,sourceHash,evidence[].lineStart-lineEnd๋ฅผ ํ์ธํ๋ค. sourcePath์๋ฌธ ํ์ผ์ ํด๋น line range๋ฅผ ๋ณด๋ฉด claim ๊ทผ๊ฑฐ๋ก ๋์๊ฐ๋ค.- chunk ๋จ์๊ฐ ํ์ํ๋ฉด ๊ฐ์
sourcePath์์lineStart-lineEnd๋ฅผ ํฌํจํ๋ source chunk๋ฅผ ์ฐพ๋๋ค.
11. ํ ์ค ๋ชจ๋ธ
Source chunk๋ ์๋ฌธ ์์น๋ฅผ ์ ๊ณตํ๋ค.
Claim์ source-aware key์ evidence๋ก ์๋ฌธ์ ๊ณ ์ ๋๋ค.
claims.json์ claim์ dedupeํ์ง ์๊ณ source ๋จ์๋ก ๊ต์ฒด/๋ณด์กดํ๋ค.
concept wiki๋ ๊ฐ์ subject์ concept claim๋ค์ ํ ํ์ด์ง์ ๋ชจ์ ๋ณด์ฌ์ฃผ๋ projection์ด๋ค.12. ์ฝ๋ ๊ธฐ์ค ์์น
| ๊ด์ฌ์ฌ | ์ฝ๋ ๊ธฐ์ค |
|---|---|
| source chunk ๊ตฌ์กฐ | src/markdown.ts MarkdownChunk, chunkMarkdown() |
| DB source chunk id | src/index-store.ts stableChunkId(sourcePath, sourceHash, ordinal, heading) |
| sourceId / claimKey | src/claims.ts stableSourceId(), sourceClaimKey() |
| LLM ์๋ต โ SourceClaim ์์ฑ | src/wiki-generator.ts buildSourceClaims() |
| source-owned generated wiki path | src/wiki-generator.ts wikiPagePath() |
| generated wiki ์ ์ฅ/checkpoint | src/indexer.ts enqueueWrite() / step6Payload() |
wiki/claims.json ํตํฉ | src/indexer.ts mergeSourceClaims() ํธ์ถ, src/claims.ts mergeSourceClaims() |
| concept wiki grouping/write | src/indexer.ts writeMergedConceptPages() |
๊ฒฝ๋ก ํ๊ธฐ ๊ธฐ์ค:
- ์ฝ๋์
wikiPagePath("A.md")๊ฒฐ๊ณผ๋generated/A.wiki.md์ด๋ค. - ๋ฌธ์์์๋ runtime wiki root๋ฅผ ๋๋ฌ๋ด๊ธฐ ์ํด
wiki/generated/A.wiki.md์ฒ๋ผ ํ๊ธฐํ๋ค. - concept page๋ runtime wiki root ์๋
wiki/concepts/Matcher.md๋ก ์ดํดํ๋ฉด ๋๋ค.
13. ํ์ฌ ๋ฐฉ์์ ํ๊ณ์ ๊ฐ์ ๋ฐฉํฅ
ํ์ฌ ๋ฐฉ์์ source file ๋จ์ ๊ต์ฒด๋ค. ์ฆ A.md์ chunk 10๊ฐ ์ค 1๊ฐ๋ง ๋ฐ๋์ด๋ A.md ์ ์ฒด hash๊ฐ ๋ฐ๋๊ณ , A.md์์ ๋์จ claim set ์ ์ฒด๊ฐ ๋ค์ ์์ฑยท๊ต์ฒด๋๋ค.
flowchart LR A["A.md<br/>chunk 10๊ฐ"] --> C["chunk #4๋ง ์์ "] C --> H["A.md ์ ์ฒด sourceHash ๋ณ๊ฒฝ"] H --> LLM["A.md ์ ์ฒด๋ฅผ LLM ์ฌ์ฒ๋ฆฌ"] LLM --> OLD["๊ธฐ์กด A.md claim 5๊ฐ ์ ๊ฑฐ"] LLM --> NEW["์ A.md claim set ์ ์ฒด ์ถ๊ฐ"]
์์:
์ค์ ์ํฅ:
- chunk #4๋ง ๋ณ๊ฒฝ
- ๊ธฐ์กด claim 5๊ฐ ์ค c2๋ง ์๋ฏธ์ ์ํฅ
ํ์ฌ ์ ์ฅ ๊ฒฐ๊ณผ:
- A.old:c1~c5 ์ ๊ฑฐ
- A.new:c1~c5 ์ถ๊ฐํ๊ณ:
- ์์ ์์ ๋ source ์ ์ฒด claim churn์ ๋ง๋ค ์ ์๋ค.
- LLM ์ฌ์์ฑ ๋๋ฌธ์ ์ํฅ ์๋ claim์ ๋ฌธ์ฅ, ์์, evidence๊ฐ ํ๋ค๋ฆด ์ ์๋ค.
- concept wiki์ ๊ฒ์ index/ranking๋ ๋ถํ์ํ๊ฒ ๋ณํ ์ ์๋ค.
๊ฐ์ ๋ฐฉํฅ:
source file ๋จ์ ๊ต์ฒด
โ chunk hash ๋น๊ต
โ ๋ณ๊ฒฝ chunk ์ฐพ๊ธฐ
โ ํด๋น chunk์ ์ฐ๊ฒฐ๋ claim๋ง stale ์ฒ๋ฆฌ
โ stale claim๋ง LLM patch
โ ์ํฅ๋ฐ์ concept wiki๋ง ์ฌ์์ฑํต์ฌ์ claim์ dependency๋ฅผ ๋ช ์ํ๋ ๊ฒ์ด๋ค.
{
"claimKey": "src:2d63174e212b2fdb:c2",
"sourcePath": "A.md",
"dependsOnChunks": ["A.md#4"],
"evidenceIds": ["src:2d63174e212b2fdb:e2"]
}์ด๋ ๊ฒ ๋๋ฉด A.md#4๋ง ๋ฐ๋ ๊ฒฝ์ฐ c2๋ง ์ฌ๊ฒ์ฆ/์์ ํ๊ณ , ๋๋จธ์ง claim์ ๊ทธ๋๋ก ๋ณด์กดํ ์ ์๋ค.