Files
pj0235-eai_agentplatform/docs/完整分析_pj0231_vs_pj006-zhilianyuan2.md
T
eaiadminandClaude Code 16d63de4e1 chore: 工作台产品化进行中的改动
把工作区里其余在制品一并入库,主要是工作台产品化的推进:

  后端:新增 capability_definition / project / my_app_center / office_skill
        接口与 action_definition / skill_definition / project / user_app_center
        模型,config 加路由健康上报。
  前端:新增 frontend/src/skills(Office 技能与 workbuddy 复刻)、
        项目管理、应用中心、能力目录页,以及配套 api / store / config;
        聊天侧新增 SpecialistChip / SpecialistPanel / SkillStrip / AppChatRail
        等组件。
  清理:移除旧 views/tools 下的单页工具(已并入工作台)、_frozen 冻结组件、
        cmd/inspect_oa_debug 调试入口,以及两份调试笔记。
  其它:文档与启动脚本同步。

(这批改动与上一提交的 SY23 工作并行进行,此前已在同一工作区内交织。)

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-17 21:32:35 +08:00

17 KiB
Raw Blame History

pj0231-eai_agentplatforming 完整分析报告(对比 + 差距 + 路线图 + 设计稿)

版本:V1.0 | 日期:2026-08-16 对比对象:pj006-zhilianyuan2(智练猿) 范围:知识库能力、考试能力、测试/自测能力、岗位与知识对应能力 原则:以实际代码为准(本项目 PRD 文档存在过时,见 §1.3)

注: 本文基于 2026-08-16 代码快照(后端 Go + Gin + GORM,检索为 brute-force 余弦 + bge-m3);数据库与向量栈已决策迁移至 MySQL 8.0 + FAISS,见 docs/db_schema.md / docs/deploy.md。


目录

  • Part A —— 现状对比
  • Part B —— 差距汇总与反向差异
  • Part C —— 改进路线图
  • Part D —— 设计稿:岗位与知识对应能力(核心)
  • Part E —— 设计要点:其余改进项
  • Part F —— 待拍板决策点与下一步

Part A —— 现状对比

A1. 一句话结论

两个项目不是同一量级:

  • pj0231 是一个极简单租户、内部专属培训平台——Go 后端约 4,900 行,11 张表,2 个角色,聚焦「看资料 → AI 答疑 → 考试验收」的窄闭环。
  • pj006 是一个多租户、多角色、带完整 AI 对练 / 岗位能力模型的通用销售培训平台——Python 后端约 1.7 万行 + 独立 engine 库,23 版 schema、40+ 张表,4 个前端。

在四个对比维度上,pj006 全部能力更全、更深;但 pj0231 在个别点上有「更实」的实现(见 §B3)。

A2. 系统定位与技术架构

维度 pj0231 pj006
定位 博昇内部培训(单企业) 通用 AI 销售培训平台(多企业 SaaS)
后端 Go + Gin + GORM + SQLite Python 3.10 + FastAPI + SQLite(per-org 分库)
前端 1 个:Vue3 + Vite + Element Plus 4 个:app / orgadmin / admin / platformadmin
角色 2(employee / admin) 多级(学员 / 组织管理员 oadmin / 平台管理员 padmin / 教练 trainer)
租户 单租户 多租户(orgs 注册表 + 每 org 一个 <org>.db)
代码量 ~4,900 行 Go ~17,200 行 Python + zlylibs/engine
数据表 11 张 40+ 张(schema v23)
AI 底座 内网 OpenAI 兼容接口(Ollama LLM + bge-m3) OpenAI 兼容路由(trainee/coach/eval 三 slot)

A3. 重要前提:pj0231 文档已过时

  • docs/PRD.md 写「FastAPI + MySQL + 不做向量检索」;实际代码是 Go + Gin + GORM + SQLite,检索已实现向量(brute-force 余弦 + bge-m3)。
  • 本项目权威信息以 eai_agentplatform/CLAUDE.md 与实际代码为准。

A4. 知识库能力对比

能力 pj0231 pj006
素材摄入 ✅ 上传→审批→转换→切片(真实跑通) ⚠️ 知识工厂骨架完备,Phase 1 解析抽取「不真跑、停 pending」
文档转换 LibreOffice + pdftotext,切片入 knowledge_chunk 设计 parse/structured/extraction_blocks 多阶段管线,未实跑
审批流 ✅ pending/approved/rejected,审批前置 ✅ 更细:working_knowledge_points 待复核 + kb_publish_records 发布链
知识组织 扁平 knowledge_chunk + knowledge_source 多层:knowledge_points → knowledge_meta → knowledge_units(统一主干)→ knowledge_chunks(带 embedding_status)
术语/规则 ❌ 无 ✅ knowledge_terms、industry_rules
检索 ✅ 混合检索(向量余弦 + 关键词兜底) ⚠️ 实跑 jieba 分词 + LIKE;向量仅文档宣称
自动出题 ❌ 无 ✅ 设计:working_questions 自动生成(待复核)
知识-题目/场景关联 仅题目挂 course_id ✅ question_knowledge_units、scene_knowledge_units、knowledge_unit_links

A5. 考试能力对比

能力 pj0231 pj006
题型 单选 / 多选 / 判断 单选 / 多选 / 判断 / 简答 essay
简答评分 ❌ 无 ✅ LLM 按 rubric 评分,得分率持久化 exam_session_grades
组卷 ✅ 按知识域 + 随机抽题 ⚠️ 固定 question_ids 列表;蓝图组卷未接考试服务
考试次数 正式考只允许一次 ✅ max_attempts + deadline
自测 ✅ 自测(即时对错、不存记录) ✅ 练习走独立 practice 模块
判分 确定性比对 选择题确定性 + 简答 LLM
成绩分析 仅存得分/正确率/明细 ✅ 维度能力分析(weak/ok/strong)+ 薄弱题 + 改进建议
错题联动 ❌ 无 ✅ 交卷错题自动入 mistake_records

A6. 测试 / 自测 / 评估能力对比

A6.1 面向学员(产品能力)

能力 pj0231 pj006
自测练习 ✅ 自测(不存记录) ✅ 每日一练 practice(游戏化:段位/星/连击/经验/积分)
错题本 ❌ 无 ✅ mistake_records(练习+考试聚合)
笔记/收藏 ❌ 无 ✅ study_notes + 收藏
学习档案/学情 ❌ PRD 明确禁止 ✅ 学习档案 dashboard + 能力对标
AI 对练复盘评分 ❌ 无 ✅ dialogue_review_scores + ReviewScoreService

A6.2 面向软件工程(自动化测试)

维度 pj0231 pj006
后端测试 ❌ 0 个 _test.go ✅ 31 个 pytest 文件
引擎测试 无 engine 层 ✅ zlylibs/engine/tests 约 20 个
测试策略文档 ❌ 无 ✅ docs/12_Test_Strategy
CI/依赖管理 无 ✅ pyproject dev deps

A7. 岗位与知识对应能力(差距最大维度)

pj0231 是结构性缺失:用户只有 role,完全没有岗位概念,也没有岗位→知识→考试的能力链。

能力 pj0231 pj006
岗位表 ❌ 无 ✅ positions
岗位↔用户绑定 ❌ 无 ✅ user_positions
岗位能力模型(洋葱) ❌ 无 ✅ competency_layers + competency_levels(L1-L4)+ competency_details
能力模型自动生成 ❌ 无 ✅ generate_competency_model
岗位↔知识映射 ❌ 无 ✅ position_knowledge_units + auto_match
岗位考试蓝图 ❌ 无 ✅ position_exam_blueprints
标准岗位/职级代码 ❌ 无 ✅ SD01_Standard_Job_Codes
岗位驱动学练考 ❌ 无 ✅ A11 学习 / A12 练习 / A13 蓝图组卷

Part B —— 差距汇总与反向差异

B1. 差距严重度总表

维度 pj0231 现状 差距严重度 是否 pj0231 定位内该补
岗位与知识对应 完全缺失 🔴 高 ✅ 是(本次核心诉求)
错题本 / 学习闭环 完全缺失 🟠 中高 ✅ 是(考试「考完即止」无闭环)
简答题 + LLM 评分 缺失 🟠 中 ✅ 是(LLM 底座已有,成本低)
自动化测试 0 测试 🟠 中高(工程风险) ✅ 是
多租户 / NPC 人格 / KPI 缺失 🔵 低 ❌ 否(与「极简内网单企业」冲突)
向量检索 ✅ 已实现 — —(反而领先 pj006)
随机 + 按域组卷 ✅ 已实现 — —(反而领先 pj006)

B2. 反向差异:pj0231 反而更「实」的点

  1. 向量检索是真实现:pj0231 混合检索端到端可用;pj006 实跑 jieba 关键词,向量仅字段预留。
  2. 随机 + 按知识域自动抽题组卷:pj0231 支持;pj006 考试为固定题目列表。
  3. 文档→文本→检索链路真实跑通:pj0231 LibreOffice/pdftotext 切片入库完整;pj006 知识工厂 Phase 1 未实跑。
  4. AI 算力点计费 + 审计日志:pj0231 有 ai_call_log;pj006 未见同等计费。

Part C —— 改进路线图

C1. 优先级(按 ROI)

优先级 项 理由
P0 岗位模型 + 岗位-知识映射 + 岗位驱动考试 最本质差距,本次核心诉求
P1 学员「我的岗位应学清单」+ 成绩按岗位聚合 P0 的自然延伸
P2 错题本 + 轻量成绩档案 补考试闭环
P2 简答题 + LLM 评分 复用 LLM 底座,成本低
P2 后端自动化测试 消除 0 测试隐患
不做 多租户 / NPC 人格 / HEP 引擎 / KPI 与极简定位冲突

C2. 分阶段总览

P0(本次落地):岗位 + 映射 + 岗位驱动考试组卷
   ↓
P1:我的岗位应学清单 · 成绩按岗位聚合 · 岗位考试蓝图
   ↓
P2:错题本 · 简答题 LLM 评分 · 自动化测试

Part D —— 设计稿:岗位与知识对应能力(核心)

完整设计见《设计稿_岗位与知识对应能力.md》,此处为完整版正文。

D1. 目标与原则

目标:落地最小岗位驱动闭环 —— 岗位 → 用户绑定 → 岗位知识映射 → 岗位驱动考试组卷。

原则:保持极简;复用现有 AutoMigrate / RequireAdmin / pickQuestions;级别词汇对齐 pj006 L1-L4 但不建独立级别表;单岗位优先。

D2. 改动点清单

现有资产 位置 改动
User internal/model/user.go 加列 PositionID *uint(可空)
ExamPaper internal/model/exam_paper.go 加列 PositionID *uint(可空)
迁移 internal/store/db.go AutoMigrate 追加 2 张新表
路由 internal/api/router.go 新增岗位端点(admin 组)
抽题 internal/api/exam.go pickQuestions 增加岗位知识映射过滤分支
种子 internal/store/seed.go 可选预置默认岗位

D3. 数据模型

3.1 position(岗位表)

type Position struct {
	ID          uint      `gorm:"primaryKey" json:"id"`
	Code        string    `gorm:"size:32;uniqueIndex;not null" json:"code"`
	Name        string    `gorm:"size:64;not null" json:"name"`
	Description string    `gorm:"type:text" json:"description"`
	Status      string    `gorm:"size:16;not null;default:active;index" json:"status"` // active / inactive
	CreatedAt   time.Time `json:"created_at"`
	UpdatedAt   time.Time `json:"updated_at"`
}
func (Position) TableName() string { return "position" }

3.2 position_knowledge(岗位知识映射,核心)

type PositionKnowledge struct {
	ID            uint      `gorm:"primaryKey" json:"id"`
	PositionID    uint      `gorm:"not null;index" json:"position_id"`
	Domain        string    `gorm:"size:16;not null;index" json:"domain"`            // company / product / sales
	CourseID      *uint     `gorm:"index" json:"course_id"`                          // 可空
	ProductID     *uint     `gorm:"index" json:"product_id"`                         // 可空
	RequiredLevel string    `gorm:"size:16;not null;default:L1" json:"required_level"` // L1/L2/L3/L4
	Weight        float64   `gorm:"not null;default:1" json:"weight"`
	IsMandatory   bool      `gorm:"not null;default:true" json:"is_mandatory"`
	CreatedAt     time.Time `json:"created_at"`
	UpdatedAt     time.Time `json:"updated_at"`
}
func (PositionKnowledge) TableName() string { return "position_knowledge" }

3.3 级别常量

const (
	LevelL1 = "L1" // 入门级
	LevelL2 = "L2" // 稳定执行级
	LevelL3 = "L3" // 复杂处理级
	LevelL4 = "L4" // 体系策略级
)
var validLevels = map[string]bool{LevelL1: true, LevelL2: true, LevelL3: true, LevelL4: true}

D4. API 设计

方法 路径 权限 说明
GET /api/positions admin 岗位列表
POST /api/positions admin 新建岗位
PUT /api/positions/:id admin 编辑岗位
DELETE /api/positions/:id admin 停用(软删)
GET /api/positions/:id/knowledge admin 岗位知识映射列表
PUT /api/positions/:id/knowledge admin 保存映射(整表覆盖)
PUT /api/users/:id/position admin 设置/清除用户岗位
GET /api/my/position 员工 我的岗位 + 应学范围(P1)

D5. 岗位驱动考试组卷(核心算法改动)

修改 pickQuestions,在 PositionID != nil 时按岗位知识映射圈定题池,否则回退原 domain 抽题:

func pickQuestions(p model.ExamPaper) ([]model.Question, error) {
	pool := store.DB.Where("status = ?", "active")

	if p.PositionID != nil {
		var pks []model.PositionKnowledge
		if err := store.DB.Where("position_id = ?", *p.PositionID).Find(&pks).Error; err != nil {
			return nil, err
		}
		domains := make([]string, 0, len(pks))
		courseIDs := make([]uint, 0, len(pks))
		for _, pk := range pks {
			domains = append(domains, pk.Domain)
			if pk.CourseID != nil {
				courseIDs = append(courseIDs, *pk.CourseID)
			}
		}
		domains = dedupe(domains)
		if len(domains) > 0 {
			pool = pool.Where("domain IN ?", domains)
		}
		if len(courseIDs) > 0 {
			pool = pool.Where("course_id IN ? OR course_id IS NULL", courseIDs)
		}
	} else {
		domains := splitDomains(p.Domain)
		if len(domains) > 0 {
			pool = pool.Where("domain IN ?", domains)
		}
	}

	var qs []model.Question
	if err := pool.Order("id ASC").Find(&qs).Error; err != nil {
		return nil, err
	}
	if len(qs) < p.QuestionCount {
		return nil, fmt.Errorf("题库题目不足:需要 %d,可用 %d", p.QuestionCount, len(qs))
	}
	if p.Randomize {
		rand.Shuffle(len(qs), func(i, j int) { qs[i], qs[j] = qs[j], qs[i] })
	}
	return qs[:p.QuestionCount], nil
}

配套:CreatePaper / UpdatePaper 追加校验——岗位考试必须已配置至少一条知识映射,否则拒绝。

D6. 前端设计

  • 导航:管理员「系统管理」下拉新增 「岗位管理」。
  • 页面:岗位列表(CRUD)+ 岗位知识映射编辑面板(domain 下拉 + 课程/产品下拉 + L1-L4 + 权重 + 必学开关)。
  • 改造:用户管理页加「岗位」下拉;考试配置表单加「关联岗位」下拉。

D7. 分阶段

  • P0:表 + API + 岗位 CRUD + 用户设岗 + 岗位驱动组卷 + 前端岗位管理页。
  • P1:学员「我的岗位应学清单」+ 成绩按岗位聚合 + 岗位考试蓝图。
  • P2:见 Part E。

D8. 明确不做

❌ 不建洋葱三层模型;❌ 不引入多租户;❌ 不做 LLM 自动生成能力模型;❌ 不做多岗位绑定;❌ 不做学情分析。


Part E —— 设计要点:其余改进项

E1. 错题本 + 轻量成绩档案(P2)

⚠️ 与 PRD 冲突需先拍板:PRD 第 7 节「无学情分析」。错题本是学员自助工具(不做管理层分析),可不冲突;学习档案/能力雷达属「学情分析」范畴,需产品重新确认是否放开。

数据模型

// MistakeRecord 错题本
type MistakeRecord struct {
	ID            uint      `gorm:"primaryKey" json:"id"`
	UserID        uint      `gorm:"not null;index" json:"user_id"`
	QuestionID    uint      `gorm:"not null;index" json:"question_id"`
	Source        string    `gorm:"size:16;not null" json:"source"` // self_test / formal
	UserAnswer    string    `gorm:"type:text" json:"user_answer"`
	CorrectAnswer string    `gorm:"type:text" json:"correct_answer"`
	Resolved      bool      `gorm:"not null;default:false;index" json:"resolved"`
	CreatedAt     time.Time `json:"created_at"`
	UpdatedAt     time.Time `json:"updated_at"`
}
func (MistakeRecord) TableName() string { return "mistake_record" }

联动点

  • 正式考 ExamSubmit 判分循环里,错题 INSERT 进 mistake_record(source=formal);自测可选不写。
  • 学员端「我的错题本」页:列表 + 「已掌握」标记(resolved=true)。

E2. 简答题 + LLM 评分(P2)

数据模型改动

  • question.type 增加 essay;answer 存 rubric 评分要点文本;options 空。
  • exam_record.detail_json 已存答题明细,可直接承载简答文本。

评分流程

  • 复用 internal/ai/llm.go,新增「评分」能力路由(或在 ai_call_log.capability 加 essay_grade)。
  • 交卷时对 essay 题调 LLM 按 rubric 打分(0~1 得分率),持久化到 detail_json。
  • 选择题仍确定性判分;总分 = Σ得分率/题数×100(对齐 pj006 算法)。

E3. 自动化测试(P2)

  • 后端:新增 _test.go,优先覆盖纯逻辑函数:isCorrect(判分)、splitDomains、pickQuestions(组卷)、ai.Retrieve 的 splitTerms/cosine。
  • 命令:go test ./...;接入 start_dev 或 CI 脚本。
  • 前端:可选,暂缓。

Part F —— 待拍板决策点与下一步

F1. 需产品/技术拍板

  1. 岗位考试课程过滤语义(D5):岗位绑定具体课程时,抽题用 course_id IN ?(严格)还是 course_id IN ? OR course_id IS NULL(宽松含域匹配)?
  2. 错题本 vs 学情分析边界(E1):PRD 禁止「学情分析」,错题本是否属于允许范围?
  3. 岗位知识映射去重(D3.2):是否加唯一约束防重复?
  4. 简答题是否本期做:P0 还是 P2?

F2. 建议的下一步

  1. 确认 F1 四个决策点;
  2. 进入 P0 编码(改动文件已列于 D2,共 6 处);
  3. P0 完成后补 isCorrect/pickQuestions 单测(借 P0 一并补测试债)。

本文件为整合版:Part A/B/C 来自《对比分析_pj0231_vs_pj006-zhilianyuan2.md》,Part D 整合自《设计稿_岗位与知识对应能力.md》,Part E 为新增其余改进项设计要点。