AZ R&D「China MVR Smart Tool(POC)」的底层平台。基于微软 PIKE-RAG 框架,围绕多轮迭代检索、Azure 文档智能解析与四路混合召回构建,交付一套可部署的知识库问答 API。历时约三个月,由 Python 服务演进为 Python + .NET 双后端 Agentic 平台。
项目于 2026 年 3 月 19 日由一次 “initial commit” 拉起,到最后一次提交 2026 年 6 月 24 日,跨度约三个月、14 个开发周。四月与五月是绝对主力期,两个月贡献了 331 次提交(占全部的 79%),六月进入收尾与部署加固。
五位实际贡献者。Yong Ma 是绝对核心,独立贡献 235 次提交(占 56%),横跨 C# 后端、Python API、Web 前端与文档;ShuaiHua Du 主攻部署、后端与数据库迁移。Kelvin Kuang 来自 Microsoft,作为 PIKE-RAG 框架方提供顾问支持。
注:git 历史中出现 7 个署名身份,其中 “Chen” 与 “chewa-git” 共用同一邮箱(lulali@outlook.com),“Kelvin Kuang / Kelvin kuang” 为大小写差异,实际归并为 5 位贡献者。
这个项目是 AZ R&D 的 China MVR Smart Tool(POC)。业务场景很具体:临床质量管理(CQM)与运营团队面对海量的研究方案(CSP)、SOP、质量文档,需要在其中快速、准确地查证信息。PIKE-RAG 承担的正是「文档理解 + 可溯源问答」这一核心引擎——把散落在数百份 PDF 里的临床知识,变成一句提问就能得到带出处、可核对的答案。
数据来源:MVR_Doc/3-Test/DocumentList_0603.csv(709 条真实文档清单)与 db_migration/seeds/seed_profiling_defaults.py(分类体系与标签定义)。研究方案示例已按客户要求脱敏(10 个真实 Study 涵盖 Oncology / Respiratory / CVRM 三大治疗领域)。
PIKE-RAG 的核心是一套多轮迭代式检索增强流程:由 LLM 规划器(Planner)驱动,反复判断「是否还需要更多证据」并自主生成新的检索 query,直到证据充分或达到跳数上限,才结合累积上下文生成带引用的答案。整条链路建立在文档智能解析与四路混合召回之上。
一份 PDF 从上传到"能被搜到",要过 4 关。关键区别不是"存了向量"而已——PIKE-RAG 会把每份文档拆成 section(章节)/ table(表格)/ figure(图片) 三种可检索单元,让检索器能同时找"哪段话在说这事"、"哪张表列了这数据"、"哪张图展示了这结构"。
LangChain loader 读文本,进入 STEP 3 增强,快得多也省 GPU。只有 PDF 和扫描件才需要走完整 4 步。为什么这么设计?不做 STEP 3 增强,LLM 检索时只会拿到孤零零一段"表 3.1"、"图 5-2"——没上下文没意义。让 LLM 提前用自然语言"解释每个表和图在说什么",相当于给 chunks 打上"业务说明",大幅提升召回相关性和引用可读性——用户看引用 [3] 弹出的是"表 3.1:阿卡替尼剂量调整表",而不是一个空白表格框。
很多人以为医药 RAG 就是"套一层 OpenAI API"——本项目完全相反。因为客户是 AZ R&D 的临床质量团队,数据是未上市药物的 CSP(临床研究方案)——数据敏感度是 GxP + 商业机密双高,数据出不了 AZ 内网。所以整套 AI 栈都部署在 AZ 内网的 GPU VM 上——LLM、Embedding、Reranker、文档解析全部本地化,零外网调用。
chunk_id + document_id + kb_id + content + metadata + dense_vector(1024) + sparse_vectorrequest.retrieve_k 覆盖 · Dense/Sparse 两路各召回 16 条,融合后取并集去重request.max_hop 覆盖 · 每轮由 LLM 判断"证据是否充足",不足则自主生成新 query,直至满足或达上限vllm/vllm-openai:v0.21.0)不同端口qwen2-5-72b-awq / bge-m3 / bge-reranker-v2-m3 / document-intelligence · 与应用层(staging namespace)物理隔离不用 Azure OpenAI GPT-4/GPT-5 云端 API(初期代码有相关适配器,已弃用)· 不用 OpenAI text-embedding-3(settings.py 里 EMBEDDING_DEPLOYMENT 默认值只是兜底占位)· 不用云端 Azure DI(cognitiveservices.azure.com 已切本地容器)· 不用 Anthropic Claude / Google Gemini——整条推理链路对外零 API 调用,连商用 CDN 都不走。
向量语义相似度检索。Embedding 走本地 bge-m3(1024 维),底层是 Milvus 2.5.10 原生 hybrid_search。已从 Chroma 完全迁移。
BM25 关键词检索,由 Milvus 内建(不再走外部 BM25 库)。补足向量召回对精确术语、编号、专有名词的漏检——例如 Study-A、SOP-0039261 这种硬 ID。
先检索细粒度「原子块」,再经 source_chunk_id 回跳到所属 section,提升定位精度。
独立图片检索通道。针对图文混排文档,直接召回相关图表证据。
下面这张时空图按 时间顺序 展示从用户点击"发送"到答案完整渲染的所有环节。三列并排:用户在界面看到什么 · 后端在做什么(含代码位置)· 通过 SSE 推送的事件。所有事件名、payload 字段、prompt 摘录都是从代码里 grep 出来的,不是示意。
v2/conversation_router.py 收 ChatCompletionsRequest,透传到 chat_completions usecase。upsert_chat_session 建/更新会话(title 取 question 前 80 字)→ insert_chat_message(role=USER)。落库失败会 logger.warning 但不中断请求。_run_pipelinedoc_ids:available(参与召回)· processing(前端提示)· missing(短路返回)。通过后打埋点 span,进入 QA workflow。issued_queries=[] · retrieved_docs=[] · retrieved_chunks=[] · round_traces={}。round_limit = request.max_hop if request.max_hop > 0 else 5。_answer()observability.start_span("qa.workflow.round"),把 round_idx 写进 span attribute。首轮 query = 原问题,跳过决策/提议;非首轮走 4.1 → 4.2。question + chunks(累积) + queries(已发) + history;解析出 {thinking, to_request: bool}。to_request=False → 立即 break 主循环,进入 STEP 5。decide_continue()_on_query_proposal_delta 回调把每个 token 通过 llm.delta 事件推给前端。propose_query()HybridRetrieverV2(Milvus 原生 hybrid_search):Dense(metric=COSINE)+ Sparse(metric=BM25)两条 AnnSearchRequest 并发发出,RRFRanker(k=60) 融合;filter_expr 限定 kb_id + doc_id in [...],禁止 KB 级全扫。返回 Documents 去重后累积到 retrieved_docs。retrieve_sections()query in issued_queries → skip_reason=duplicate_query(去重硬闸);若 query is None → skip。都不消耗 round 配额。llm.delta 事件的 text_delta 顺序拼接、渲染。答案中的 <pike_rag_cite>N</pike_rag_cite> 标签在渲染时被解析为可点击的 [N] 引用,悬停显示原文。evidence_assembler.to_reference_chunks(retrieved_docs, retrieved_chunks) 把累积证据按顺序编号,用 <pike_rag_cite>1</pike_rag_cite> ... 标签标注。调 LLM 用 generation_qa_with_reference prompt——严格要求"仅依据 context 作答",context 为空必须拒答且不含任何引用标签。generate()type=heartbeat 空事件。外部调用方可 filter type == "heartbeat" 忽略。append_heartbeat()<pike_rag_cite> 映射到 references_ready.count 对应的 chunk 数组,把 [1][2] 变成可悬浮/点击的高亮引用。用户消息 + 助手消息都进 chat_messages 表。_persist_assistant_messages(collector, ...):从 MessageCollector 收集到的 reasoning/tool/answer 三类事件按 message 批量入库;observe_chat_request_duration() 埋 Prometheus 指标。response.close(final_status) 关闭 SSE 队列。_persist_assistant_messagesdata: [DONE]\n\n_build_answer_message() ; chat_completions.py:91下面是 直接从代码抠出来的原文——没做任何改写,包括英文、格式化标记 {{}}、注释。三个 prompt 都在 src/pikerag/prompts/qa/ 目录下,微软 PIKE-RAG 框架的原始定义。
# system You are a helpful AI assistant good at context reading and question addressing. # user template # Task Given the question and context, your task is to thoroughly analyze the context and decide whether additional information is required for you to address the question. Aim for a detailed and precise answer. If the situation warrants further details, you should decide to request for more information. # Output Format Please output in following JSON format: { "thinking": <A string. Your thinking for this task, should be in {response_language}.>, "to_request": <A string. "Yes" to request more, "No" to indicate the context is sufficient.> } # Context {context_if_any} # Question to Be Answered {content} # Your Output
关键 parser 逻辑:to_request 被解析成 bool——output["to_request"].strip().lower() in ["yes","y","true","1"];解析失败默认 True(保守地继续检索,而不是提前停)。
# user template(system 同上) # Task Given the question and context, your task is to thoroughly analyze the context and formulate a specific query requesting additional information that is helpful to address the question. Here are some notes for the "query" part you should follow: - Ensure that your query is detailed and self-contained, including all necessary identifiers and context. - Avoid using ambiguous pronouns such as 'he', 'it', etc. Instead, specify relevant details such as the specific file, product, or other pertinent information, so that the query can be understood and addressed independently of any preceding dialogue. - Never output same query if it has already been asked. If the historical query is important but no relevant context is found, consider asking about a different aspect or rephrasing the query to obtain complementary information. - Your response "query" would be used to retrieve more information from a knowledge base or search engine, format it in a suitable way. # Output Format { "thinking": <String, in {response_language}>, "query": <String, in {response_language}> } # Context {context_if_any} # Question to Be Answered {content} # Queries You Already Asked {queries_if_any} # Your Output
关键 parser 逻辑:query.strip() == "" → None(None 会触发 skip_reason=query_none,跳过本轮)。去重硬闸在 workflow 层:if query in issued_queries: skip——即使 LLM 忘了"不重复"规则,代码也拦得住。
# user template # Task Given the question and context, your task is to read the context carefully and give your answer to the question. Each context chunk is labeled with a special citation tag like <pike_rag_cite>1</pike_rag_cite>, <pike_rag_cite>2</pike_rag_cite>, etc. When your answer uses information from a specific context, add the corresponding citation tag, following these rules: - Cite at most ONCE per paragraph for the same source. Do not repeat. - If a sentence merely paraphrases already-cited material, do NOT cite it again. - For bullet lists, place the citation at the END of the bullet. - Do not cite for obvious facts, definitions the user already knows. - Place the citation tag at the END of the smallest meaningful unit. - Aim for a clean reading experience: one citation per paragraph or bullet. Important: You must answer ONLY based on the provided context. If the context section is empty or does not contain information relevant to the question, respond with a short refusal message in {response_language}. Do NOT answer from your own knowledge. Do NOT include any citation tags in the refusal message. # Output format { "answer": <String with inline <pike_rag_cite>N</pike_rag_cite> tags>, "rationale": <String, in {response_language}> } # Context, if any {context_if_any} # Question {content}{yes_or_no_limit} Let's think step by step.
关键 encode 逻辑:每条 chunk 被自动装成 <pike_rag_cite>{idx+1}</pike_rag_cite> {content} 格式插入 context_if_any;context_len_limit=80000 字符硬上限。输出后处理:reindex_citations()(citation_utils.py)把 <pike_rag_cite> 标签转为用户友好的 [N];拒绝语因不含标签,references 数组会被自动清空。
emit 出现的全部事件类型)从 qa_conversation_workflow.py + chat_completions.py grep 出的全部 20 种事件。SSE 帧格式统一:data: {"type": "...", "id", "created", "model", ...}\n\n,最后一帧固定是 data: [DONE]\n\n。
证据来源:grep -n 'event_type=' src/api/infrastructure/workflow/qa_conversation_workflow.py src/api/application/conversation/usecases/chat_completions.py src/api/infrastructure/workflow/qa_conversation_workflow_v2.py
检索前对文档做三态分流,仅对已完成索引的文档执行 RAG:
面向 reasoning 类模型的长静默期做工程加固:
答案的可信度由引用标签闭环保证:
前面讲了「四路混合召回 + 五轮决策」的骨架,这里把真实的 qa_conversation_workflow.py 主循环拆开来看——从用户点击"发送"到答案落地,中间有一整台状态机在运转:emit 事件流、round span、决策/提议/去重、并行观测埋点、最终生成。这是理解"为什么慢/为什么答得对"的关键结构。
从 HTTP 请求接收 question、doc_ids、max_hop、history_messages。round_limit = request.max_hop if request.max_hop > 0 else 5——用户可传入自定义上限,默认 5 轮。
装配 issued_queries=[]、retrieved_docs=[]、retrieved_chunks=[]、round_traces={} 四个游标,贯穿整个循环共享状态。
每一轮进入 with observability.start_span("qa.workflow.round")——所有耗时、决策结果、命中数都进 span attribute,产品可以在 Grafana Tempo 上看每一轮的火焰图。
如果本轮是 round_idx == 0,query 就是原始 question;否则调用 Query Planner 两阶段决策:
把 question、当前 chunks(已累积)、queries(已发过的)和 history_messages 打包成一条 message,调 LLM 让它自己评估证据是否充足。返回 (should_continue, decision_output)——如果 should_continue == False,跳出循环,进入生成阶段。
reasoning 模型(gpt-5 类)在这里有专门的 qa_conversation_workflow_v2 走独立分支,避免思维链干扰结构化输出。
Query Planner 的第二个能力:基于当前证据,生成一条自包含的新查询——强制要求带全部标识符、禁用"它/他/上述"等代词、不得与 issued_queries 重复。
去重是硬闸:if query in issued_queries: skip_reason=duplicate_query, continue——防止 LLM 反复问同一个问题浪费预算。
把新 query 送进 PikeragRetrievalExecutorAdapter.retrieve()——底层最终调 HybridRetrieverV2(实际是 Milvus 原生 hybrid_search 的 alias,见下一小节的复查说明)。返回的 Document 累积到 retrieved_docs,chunks 去重后加到 retrieved_chunks。
retrieval_count += 1 和 retrieval_duration_seconds += elapsed 每一轮累加,最后写入 span:qa.retrieval.count、qa.retrieval.total_duration_seconds。
循环结束(决策停止 或 用尽 round_limit)后,evidence_assembler.to_reference_chunks() 把累积的 chunks 装配成引用块,交给 PikeragAnswerGeneratorAdapter.generate()——LLM 基于所有累积的证据生成最终答案,通过 on_delta 回调把 token 流式推给前端。
输出 JSON 里包含 answer(含 [N] 引用标号)+ reference_chunks(编号对应的原文片段),前端把 [N] 变成可点击的高亮引用。
证据来源:src/api/infrastructure/workflow/qa_conversation_workflow.py(V1,round loop 主循环在 L869) · qa_conversation_workflow_v2.py(v2,reasoning 模型分支) · src/api/infrastructure/retrieval/pikerag_query_planner_adapter.py(Planner 两个能力 decide_continue + propose_query)
初版报告基于设计文档写的是"三代 Retriever 演进"——这个说法不准确。经代码复查(grep new/import 追踪谁在实例化每个类,再核对 registry.py 的路由注册),真相是:只有两个真实的实现——PIKE-RAG 原生的 Chroma 版本 HybridRetriever,以及项目自研的 Milvus 版本 HybridRetrieverV2Milvus。第三个类名 HybridRetrieverV2 实际是后者的 alias——新代码用它的名字导入,但拿到的是 Milvus 类。
docs/design/001-architecture.md 得出的推论,没有交叉验证代码。grep -n "class Hybrid\|import Hybrid" src/ 验证):src/api/infrastructure/retrieval/hybrid_retriever_v2.py 只有一行有效代码:from ...hybrid_retriever_v2_milvus import HybridRetrieverV2 # noqa: F401——纯 re-exportHybridRetrieverV2 的调用点(QA workflow v2、invocation_retrieval_service)拿到的都是 Milvus 类persist_dir 本地目录,无横向扩展src/pikerag/),未针对大规模优化qa_conversation_workflow.py:427(V1 主 QA workflow)knowledge_base_vectorize_service.py:64(向量化服务)invocation_retrieval_service.py:127(invocation test)
DOCUMENT_ID / METADATA)随查询一次返回qa_conversation_workflow_v2.py:946(V2 QA workflow,reasoning 模型分支)invocation_retrieval_service.py:159(invocation test)HybridRetrieverV2 alias 名导入
from api.infrastructure.retrieval.hybrid_retriever_v2_milvus import HybridRetrieverV2 # noqa: F401HybridRetrieverV2 导入,但实际类是 HybridRetrieverV2MilvusChroma 链路(HybridRetriever)处理 V1 QA workflow、知识库向量化、invocation test 老分支——是项目冷启动就在用的路径,未被删除。 Milvus 链路(HybridRetrieverV2Milvus)处理 V2 QA workflow(reasoning 模型专用分支)和 invocation test 新分支——是新加的路径,专门解决 reasoning 模型(gpt-5 等)的输出兼容问题。
接手要问的问题:生产实际流量走 V1 workflow(Chroma)还是 V2 workflow(Milvus)?如果两者都活着——数据同步机制是什么?向量化服务把 chunk 写进 Chroma 之后,什么时候、由谁写进 Milvus?这是接手第一天必须搞清的问题,报告里其他判断都依赖这个答案。
验证方法:grep -rn "HybridRetriever(" src/(不带 V2 后缀)找 Chroma 调用点;grep -rn "HybridRetrieverV2" src/ 找 Milvus 调用点;两个 workflow 文件对比看流量入口。
对每一路召回结果(Dense、Sparse),第 rank 位的文档贡献分数 1 / (k + rank),两路分数直接相加得到最终排名。k=60 是 Milvus 默认值,平衡"高排位强化"与"低排位不被淹没"。这种融合方式不需要调参加权,也不依赖不同索引分数的绝对值可比性——Dense 的 cosine 距离和 Sparse 的 BM25 分数量纲完全不同,RRF 用"排名"消除了这个问题。Chroma 链路没有这个融合器——PIKE-RAG 原生实现的融合方式(应用层排序)没有 RRF 这么好的鲁棒性。
Section-04 讲过 PIKE-AGENT 是 .NET 侧的 Agentic 后端。这里下钻——它不是一个大 LLM prompt,而是一套 Definitions 目录:13 个专职 Agent + 6 个可复用 Skill,通过 load_skill() 递归调用,走的是 Harness 模式(LLM 动态判断走哪条路,而不是固定 workflow)。
每个 Agent 是一个 v1.agent.yaml,定义 instructions(系统提示词)、skills(允许调用的技能)、model.poolId(用哪个模型池)、maxTurns(agentic loop 上限)。分成三大域:
路径 src/pike-agent/src/Modules/Pike.Agentic/Definitions/agents/*/v1.agent.yaml
Skill 是 Agent 可以调用的子任务模板——一个 skill 有自己的 instructions(提示词)、allowedTools(限定能用的工具)、metadata(版本)。Agent 用 load_skill("xxx") 递归进入下一个 skill 上下文,形成 skill chain。
kb_find_documents)→ Phase 3 命中文档定向阅读(kb_get_outline + kb_read)。设计初衷是解决"只搜文本、不找文档"的召回盲区。mvr-pharma 主 Agent 根据意图判断是业务问题还是闲聊——业务问题就 load_skill("mvr-knowledge-qa");后者又根据 replan 结果判断"资料够不够",够了 load_skill("mvr-grounded-answer") 生成答案,不够则回到 knowledge-qa 深挖。
mvr-pharma/v1.agent.yaml)—— 硬性上限,防止 skill 递归死循环。
项目演进中引入了一套 .NET 重写(历史上的 pikerag-net,现为 pike-agent)。两个后端共享同一 PostgreSQL 数据库,由 Nginx 按 URL 前缀路由共存:Python 承载 v1/v2 检索问答,C# 承载 v3 Agentic 与知识平台能力。
基于 React + Ant Design 与 @ant-design/x 会话组件构建,含知识库管理、Chat Playground、工作流可视化(@xyflow/react + dagre + mermaid),支持 i18n 与流式 SSE 渲染。
Docker Compose / Helm 双形态部署,内建 RAGAS 评测框架与纯检索基准(bge-m3 vs Azure)。
前四节讲了「代码里有什么」,这一节讲「作为一次真实的商业交付,它是如何跑完的」。以下 8 张卡片全部来自项目内部的 MVR_Doc/ 目录:709 条文档清单、12 份周报、UAT 材料、部署手册。所有客户标识(人名、内网主机、Study 代号、SharePoint 路径)均已脱敏处理。
项目按标准企业级交付六段组织,每段都有独立的产物目录。UAT 段是本次交付的最大工作量重心。
709 份知识库文档并非一次性灌入——最早的资料来自 2022-06,但 绝大部分(约 60%)集中在 2026-04 系统冷启动期。以下柱图按月粒度展示上传数量,深色柱是三次批量导入的峰值。
整个项目所有文档汇总到 一个 KB(kb_<id>)——不做业务分片,检索通过元数据过滤实现。
按文件大小分布(709 份):
从 FilePath 一级目录归纳。General、China Local Process、Study protocol 三巨头是最核心的业务资产。
Study protocol 目录下共 66 份 CSP 相关文档,覆盖 10 个真实临床研究方案。头部方案(Top 4)占 Study 总量 64%,说明本次 POC 聚焦在 少数重点在研药物。方案代号已按客户要求脱敏,此处只披露治疗领域。
生产部署跑在客户内网的一台 RHEL9 GPU VM 上,用 HashiCorp Nomad + Terraform + Makefile 编排。应用层与推理层分别在两个 namespace,通过本地回环通信。2026-06-03 完成从旧 docker-compose 到 Nomad 的切换,独占标准端口 80/443。
项目按周节奏推进(微软 Industry Solutions 交付方向 AZ R&D 提交的 Weekly Status Update),下方按周展示每周最关键的工作重点。深色圆点为里程碑周。
从周报「项目风险」页汇总合并出 9 个独立风险条目——2 条已关闭,7 条至 06-22 仍在跟踪。左侧色条表示风险级别:高 / 中 / 低/已关闭。
数据来源:本节全部内容来自项目仓库内的 MVR_Doc/ 目录——
3-Test/DocumentList_0603.csv(709 条真实文档清单,通过 Python 聚合分析)、
0-Project Managment/AZ R&D_MVR_Weekly Status Update_*.pptx(12 份周报,通过 python-pptx 解析)、
4-Deployment/*.docx(安装配置指南)、
deploy/nomad/deploy-staging.md(生产部署手册)。
无任何外部网络访问:SharePoint、生产 VM、UAT 系统均未接触。人名、内网主机、Study 代号、SharePoint URL、上传者 UUID 已全部脱敏。
本节的判断依据全部来自项目内部真实材料:docs/remediation-plan.md(整改记录,2026-05-28 最后更新,列出 P0/P1/P2 全部技术债)· 12 份周报里末次仍进行中的 7 个风险 · docs/features/{new, in-progress, deferred} 三个状态目录 · Pike.GraphRAG 设计文档(v0.6,2026-05-26)。不是空穴来风的建议,是团队已经写在纸上、但还没干完的活。
代码规模已达 55,500 行 · 916 文件 · 18 个模块。当前依赖链过深(GraphRAG → Agentic → Knowledge → Platform → Common),改一处触发多处重编译。
src/vllm 容器 + vLLM OpenAI 兼容 API 替代。需删 Pike.Worker 模块(3,631 行)+ Worker Host(28 行)+ Dockerfile/docker-compose/Nomad 相关配置。Pike.Common(纯抽象)+ Pike.Infrastructure(S3/Redis/Hangfire)+ Pike.ServiceDefaults(OTel + Aspire wiring)三层。Pike.Evaluation(约 3,000 行)。*.Abstractions csproj,只装接口 + DTO + 事件契约,模块间只引 Abstractions。收益:编译隔离 + 测试友好 + 宿主项目瘦身。已经能跑,但结构、类型安全、可维护性上有明确改进空间——大文件、Raw SQL、重复 PackageReference。
QaWorkflowContext.cs(843)、AgentFactory.cs(808)、Endpoints/EvalRuns.cs(909,随 Evaluation 拆分解决)、Endpoints/Agents.cs(506)。建议:Context 提取 Step 逻辑为 partial class;Factory 按 Agent 类型拆多个;Endpoints 按 CRUD 拆分。Directory.Build.props 中为 src/Modules/** 加条件引入通用基础包,各模块 csproj 只声明特有包。GraphMergeService.PersistMergedGraphAsync() 用原始 SQL 拼 INSERT ... ON CONFLICT DO UPDATE,无编译时检查。改用 EF Core ExecuteUpdateAsync 或 Npgsql bulk copy helper 保持类型安全。poolId 每次 db-init 都覆盖 DB。已通过统一 YAML 临时修复,但需增加 SyncPolicy: CreateOnly | AlwaysSync 语义,避免 seed 覆盖运行时配置。从 12 份周报里追踪出来 —— 06-22 最新一份周报里仍在跟踪、未关闭的风险条目。这些不是技术债,是"业务尚未闭环"的活。
multi-hop-retrieval skill 是一个尝试性补丁(强制三阶段 + 至少 8 次工具调用),但根本设计尚未落地。来自设计文档里明确规划、正在或计划推进的能力扩展 —— 这些不是"修 bug",而是"未来路线"。
kb_search · claim_search · claim_conflicts。kb_list_documents(列表浏览)和 kb_find_documents(内容检索)——Agent 选工具成本高。设计收敛为一个新工具 kb_discover_documents,支持浏览、结构化过滤、语义召回三类检索,保留分页契约。src/api/interface/http/routers/registry.py):
[V1-removed])——admin/auth/document/kb/workflow 全下/api/v2/chat/* + chat history/api/v3/*(主力) + /api/v1/*(自己的 legacy 兼容层,跟 Python V1 完全无关)src/api/interface/http/routers/registry.py(V1 全注释)· routers/v2/conversation_router.py(V2 chat 主端点) · pike-agent/**/Endpoints/*.cs(.NET 只有 v1 + v3)主报告聚焦「历史 / 架构 / 交付 / Roadmap」;实测发现的 Bug 明细、真实模型接入过程、以及最新一次端到端测试报告, 都拆到了 3 个独立子页。每个子页都可以单独发给同事;主报告顶部导航条常驻,任何时候都能一键跳转。
routes.tsx(180 行单一权威源) +
实际点开每个菜单,画出 4 大板块 · 25 个功能页 · 8 个内置任务流程 · 13 个 Agent 全清单。
ornith-1.0-35b-mtplx +
nomic-embed-text-v1.5 + bge-reranker-v2-m3)+ NMPA 官方说明书替换 Demo 语料。
Part II · 跑起来 — 端到端测试 6 环节全通 · 64 次真调用统计。
Part III · 一路的坑 — 235 冷启动 + 真模型接入过程踩到的 7 个 Bug 时间线。
Part IV · 最新运行态 — Milvus 中断根因、错误误报修复、阿司匹林问题回归,以及 Home AI Hub v0.3.0 的 tools / SSE / 768 维 / rerank 实测。
为什么拆:这两块附录都是「一次性深度调查 + 长期演进证据」性质,主报告如果全塞进来会超过 2600 行, 重要的架构叙事会被淹没。附录一回答「项目怎么来的 · 有些什么」,附录二回答「真的能跑吗 · 一路发现了什么」, 主报告聚焦「WHAT / WHY」,附录承载「HOW / EVIDENCE」。
下面的三阶段划分是基于业务价值 × 技术风险两个维度综合排出的建议,仅供项目组参考。所有项都可在上面 4 类问题里找到对应条目。
本节全部结论的证据来源:
docs/remediation-plan.md(P0-P2 完整清单,2026-05-28)·
docs/design/pike-graphrag-project-design.md(v0.6,2026-05-26)·
docs/design/claim-extraction-architecture.md(Claim 溯源架构)·
docs/design/303-document-discovery-tool.md(工具收敛设计)·
docs/design/501-api.md(V3 API 设计,版本策略)·
12 份周报(MVR_Doc/0-Project Managment/AZ R&D_MVR_Weekly Status Update_*.pptx 里 04-02 到 06-22 的风险追踪)。
Roadmap 三阶段是基于以上材料的综合建议,不代表项目组已有的正式决议。