flowchart TD
A[walk data/**/*.md, sha256 each] --> B{path in manifest?}
B -- no --> U[upload to store]
B -- yes --> C{sha changed?}
C -- no --> S[skip, unchanged]
C -- yes --> D[delete old doc id] --> U
U --> P[poll the indexing operation until done]
P --> M[upsert manifest: path, sha, doc id]
A --> R{manifest path missing on disk?}
R -- yes --> X[delete doc from store, drop manifest row]
R -- no --> S
M --> I{set of path+sha changed?}
S --> I
X --> I
I -- no --> K[corpus index unchanged]
I -- yes --> G[summarize new files with flash-lite, one line each] --> J[store corpus_index]
classDef decision fill:#f4d35e,stroke:#b8991f,color:#1a1a1a
classDef start fill:#e9ecef,stroke:#6c757d,color:#1a1a1a
classDef net fill:#5ee6c8,stroke:#1f9c86,color:#1a1a1a
classDef local fill:#6ea8ff,stroke:#2f5fc4,color:#1a1a1a
classDef idx fill:#9d8cff,stroke:#5b4bcc,color:#1a1a1a
class B,C,R,I decision
class A start
class U,D,P,X net
class S,M,K local
class G,J idx
未更改的文件会被跳过。已更改的文件会先删除旧文档,然后重新上传。从磁盘消失的文件会从存储中被删除。
每次上传都是一个返回长时间运行操作的 multipart POST,在你信任文档 ID 之前,你需要轮询直到 done。四个上传并行运行。串行情况下,一个包含 71 个文件的语料库大约需要十分钟。并行情况下,只需几分钟。
meta:=map[string]any{"displayName":displayName,"chunkingConfig":map[string]any{"whiteSpaceConfig":map[string]int{"maxTokensPerChunk":400,"maxOverlapTokens":60,},},}// multipart/related: part 1 is this JSON, part 2 is the markdown bytes// POST /upload/v1beta/{store}:uploadToFileSearchStore// with X-Goog-Upload-Protocol: multipart
{"systemInstruction":{"parts":[{"text":"...the lawbook..."}]},"contents":[{"role":"user","parts":[{"text":"PROPOSAL:\n...\n\nANALYSIS FROM CALL 1:\n{...}\n\nSearch the corpus with the retrieval queries above, then reply with the JSON contract."}]}],"tools":[{"fileSearch":{"fileSearchStoreNames":["fileSearchStores/abc123"]}}],"generationConfig":{"responseMimeType":"application/json","temperature":0.7}}
在读取之前,一小堆用纯 Go 编写的确定性检查会在每个草稿上运行:长度限制,禁止 markdown,最多一个问题,禁止“参见点 N”引用,每个引用的法律都得到解析。
flowchart TD
A[call 2: search + draft, JSON mode] --> B{reply parses as JSON?}
B -- no --> F[resend once without JSON mode, extract first object] --> C
B -- yes --> C[resolve every cited law number to file:line]
C --> D{all citations resolve?}
D -- no --> R
D -- yes --> E[deterministic checks: length, no markdown, one question max, distinct openers]
E --> G{checks pass?}
G -- no --> R{attempts left?}
R -- yes --> H[append the failures to the user message] --> A
R -- no --> S[ship the draft with failures listed]
G -- yes --> V[call 3: reviewer pass, verdict + objections]
V --> W{verdict?}
W -- ship --> O[return JSON with sources and applied laws]
W -- revise, rounds left --> H
W -- revise, no rounds --> S
classDef decision fill:#f4d35e,stroke:#b8991f,color:#1a1a1a
classDef llm fill:#5ee6c8,stroke:#1f9c86,color:#1a1a1a
classDef local fill:#6ea8ff,stroke:#2f5fc4,color:#1a1a1a
classDef bad fill:#ff9a5c,stroke:#c4602a,color:#1a1a1a
classDef good fill:#9d8cff,stroke:#5b4bcc,color:#1a1a1a
class B,D,G,R,W decision
class A,F,V llm
class C,E,H local
class S bad
class O good