diff --git a/internal/bizdev/service.go b/internal/bizdev/service.go index 46345d70..b2fa1d59 100644 --- a/internal/bizdev/service.go +++ b/internal/bizdev/service.go @@ -6,6 +6,7 @@ import ( "fmt" "os" "path/filepath" + "strings" "time" "chat-agent-system/internal/config" @@ -68,18 +69,31 @@ func (s *Service) ExecuteTask(ctx context.Context, req TaskRunRequest) (*TaskRun }) } - // 自动补充知识库检索 (如针对 research 与 feasibility_reg) + // 自动补充知识库检索 (如针对 research、feasibility_reg、cleanroom_spec、prelim_design 等阶段) hits := req.KnowledgeHits - if len(hits) == 0 && (req.TaskKey == "research" || req.TaskKey == "feasibility_reg") { - if kbHits, err := s.kb.Search(ctx, req.ProjectName+" "+req.DeviceType, 5); err == nil && len(kbHits) > 0 { - for _, kh := range kbHits { - hits = append(hits, squad.KnowledgeHit{ - DocCode: kh.DocCode, - Category: kh.Category, - Title: kh.Title, - Content: kh.Content, - Source: kh.Source, - }) + if len(hits) == 0 && (req.TaskKey == "research" || req.TaskKey == "feasibility_reg" || req.TaskKey == "cleanroom_spec" || req.TaskKey == "prelim_design") { + device := req.DeviceType + if device == "" && req.Fields != nil { + device = req.Fields["device_type"] + } + market := req.TargetMarket + if market == "" && req.Fields != nil { + market = req.Fields["target_market"] + } + searchQuery := strings.TrimSpace(req.ProjectName + " " + device + " " + market) + if searchQuery != "" { + if kbHits, err := s.kb.Search(ctx, searchQuery, kb.SearchOptions{Limit: 5}); err == nil && len(kbHits) > 0 { + for _, kh := range kbHits { + hits = append(hits, squad.KnowledgeHit{ + DocCode: kh.DocCode, + Category: kh.Category, + Title: kh.Title, + HeadingPath: kh.HeadingPath, + Content: kh.Content, + CiteKey: kh.CiteKey, + Source: kh.Source, + }) + } } } } diff --git a/internal/squad/context.go b/internal/squad/context.go index d69d27b3..8158341f 100644 --- a/internal/squad/context.go +++ b/internal/squad/context.go @@ -74,7 +74,7 @@ func (cm *ContextManager) FormatPromptContext(wsDir string, role string) (string b.WriteString("### ⚖️ 法规与标准快照(参考依据)\n") lines := strings.Split(string(kbData), "\n") for _, l := range lines { - if strings.HasPrefix(l, "### [") { + if strings.HasPrefix(l, "### ") && strings.Contains(l, "[") { b.WriteString("- " + strings.TrimPrefix(l, "### ") + "\n") } } diff --git a/internal/squad/models.go b/internal/squad/models.go index aadea7b3..4558ad9f 100644 --- a/internal/squad/models.go +++ b/internal/squad/models.go @@ -110,11 +110,13 @@ type MaterialItem struct { // KnowledgeHit 法规知识库检索命中条目 type KnowledgeHit struct { - DocCode string `json:"doc_code"` - Category string `json:"category,omitempty"` // standards, guidance, laws, catalog - Title string `json:"title"` - Content string `json:"content"` - Source string `json:"source"` + DocCode string `json:"doc_code"` + Category string `json:"category,omitempty"` // standards, guidance, laws, catalog + Title string `json:"title"` + HeadingPath string `json:"heading_path,omitempty"` + Content string `json:"content"` + CiteKey string `json:"cite_key,omitempty"` + Source string `json:"source"` } // PriorDocItem 前序阶段归档文档 diff --git a/internal/squad/workspace.go b/internal/squad/workspace.go index 6dd0bffa..26e5615e 100644 --- a/internal/squad/workspace.go +++ b/internal/squad/workspace.go @@ -356,17 +356,26 @@ func (e *WorkspaceEngine) buildContextSystem(workDir string, req WorkspacePrepar // 5. knowledge/ if len(req.KnowledgeHits) > 0 { var kbBuilder strings.Builder - kbBuilder.WriteString("# 法规与标准检索条文摘录\n\n") + kbBuilder.WriteString("# 权威法规与技术标准引用库 (Regulatory Knowledge Hits)\n\n") + kbBuilder.WriteString("以下为针对本项目研发与注册需求命中的权威法规、国家标准(GB)与行业标准(YY)条款。\n") + kbBuilder.WriteString("在输出交付物时,请结合上下文使用,并显式标注【引用标记 (CiteKey)】标明出处。\n\n") for _, hit := range req.KnowledgeHits { - kbBuilder.WriteString(fmt.Sprintf("### [%s] %s %s\n\n%s\n\n> 来源: %s\n\n---\n\n", - strings.ToUpper(hit.Category), hit.DocCode, hit.Title, hit.Content, hit.Source)) + kbBuilder.WriteString(fmt.Sprintf("### [%s] %s %s\n\n", strings.ToUpper(hit.Category), hit.DocCode, hit.Title)) + if hit.HeadingPath != "" { + kbBuilder.WriteString(fmt.Sprintf("- **章节路径**: %s\n", hit.HeadingPath)) + } + if hit.CiteKey != "" { + kbBuilder.WriteString(fmt.Sprintf("- **引用标记 (CiteKey)**: `%s`\n", hit.CiteKey)) + } + kbBuilder.WriteString(fmt.Sprintf("- **来源**: %s\n\n", hit.Source)) + kbBuilder.WriteString(hit.Content + "\n\n---\n\n") } _ = os.WriteFile(filepath.Join(ctxDir, "knowledge", "hits.md"), []byte(kbBuilder.String()), 0o644) contextItems = append(contextItems, ContextItem{ File: "context/knowledge/hits.md", Description: "法规知识库中命中的医疗器械分类、国家标准与指导原则", AuthorityLevel: "reference_standard", - Guidance: "合规与技术论据源。引用必须带标准号;涉及审批结论需标注'需向药监局审评中心确认'", + Guidance: "合规与技术论据源。引用必须标注标准号与引用标记 (CiteKey);涉及审批结论需标注'需向药监局审评中心确认'", }) }