ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

Edict系统工程化改造与扩展实践指南

Edict系统工程化改造与扩展实践指南

1. 项目概述与工程化改造路径

Edict系统经过前期的部署启动和使用实战阶段后,正式进入二次开发与扩展阶段。这个阶段的核心目标是将系统从"可用"推进到"可迭代"的平台级别,建立完整的工程化改造路径。不同于简单的功能堆砌,真正的工程化改造需要关注以下几个关键维度:

  • 代码结构清晰度:建立明确的代码地图和职责边界
  • 扩展性设计:前后端分离的契约式开发模式
  • 稳定性保障:状态机设计、异常处理和回滚机制
  • 交付标准化:构建、测试、发布的完整流水线
  • 运维可视化:日志、监控、配置的集中管理

当前系统已经形成两条明确的开发主线:

  1. 根目录看板主线:位于项目根目录下,包含dashboard、scripts等目录,特点是改动直观、验证成本低,适合快速迭代面板扩展和轻量级功能增强。
  2. edict/全栈主线:位于edict目录下,包含完整的后端架构和前端实现,适合长期架构演进和服务层抽象。

2. 代码结构与职责边界

2.1 核心目录结构解析

进入二次开发阶段,首先需要建立完整的代码地图。以下是关键目录的职责划分:

agents/ # Agent人格定义、职责边界、输入输出规范 scripts/ # 数据同步脚本、定时任务、运维脚本 dashboard/ # 看板服务、轻量级接口聚合 edict/backend/ # FastAPI核心后端、服务层抽象 edict/frontend/ # 前端页面与组件 data/ # 看板依赖的JSON数据源 tests/ # 单元测试与端到端测试

2.2 修改落点判断逻辑

当需要进行功能修改或扩展时,可按以下决策树确定修改位置:

  1. 改页面展示:优先查看edict/frontend
  2. 改接口返回:
    • 简单接口:dashboard/server.py
    • 核心接口:edict/backend
  3. 改任务状态:
    • 检查dashboard/server.py
    • 同步修改store.ts
    • 更新后端状态模型
  4. 改角色行为:
    • 修改agents/*/SOUL.md
    • 更新权限矩阵
  5. 改数据同步:
    • 调整scripts/下的同步脚本
    • 更新run_loop.py中的任务列表

3. 后端扩展实践

3.1 契约优先的开发模式

后端扩展必须遵循"契约优先"原则,在编码前明确三类核心契约:

  1. 状态契约:
class TaskState(str, Enum): TAIZI = "Taizi" # 待办状态 ZHONGSHU = "Zhongshu" # 审议中 MENXIA = "Menxia" # 复核中 DOING = "Doing" # 执行中 QA = "QA" # 质量检查 DONE = "Done" # 已完成
  1. 数据契约:
class TaskBase(BaseModel): id: str = Field(..., min_length=3) title: str = Field(..., max_length=100) state: TaskState assignee: Optional[str] created_at: datetime = Field(default_factory=datetime.now)
  1. 接口契约:
@app.get("/tasks/{task_id}", response_model=TaskOut) async def get_task(task_id: str = Path(..., min_length=3)): """获取任务详情""" task = await TaskService.get(task_id) if not task: raise HTTPException(404, "Task not found") return task

3.2 状态机设计与实现

状态流转是后端核心逻辑,需要严格实现:

STATE_TRANSITIONS = { "Taizi": ["Zhongshu"], "Zhongshu": ["Menxia", "Taizi"], "Menxia": ["Assigned", "Zhongshu"], "Assigned": ["Doing"], "Doing": ["QA"], "QA": ["Review", "Doing"], "Review": ["Done", "Doing"] } def validate_transition(current: str, next_state: str) -> bool: """验证状态流转是否合法""" allowed = STATE_TRANSITIONS.get(current, []) return next_state in allowed

注意事项:状态变更必须保证原子性,通常需要结合数据库事务实现。对于关键业务状态,建议记录完整的状态变更历史。

4. 前端扩展策略

4.1 组件化开发模式

前端扩展采用标准的组件化开发流程:

  1. 数据准备层:在scripts/下添加数据生成脚本
  2. 接口层:在后端添加API路由
  3. 前端API层:封装接口调用方法
  4. 组件层:实现展示组件
  5. 状态管理:集成到全局store
  6. 页面集成:注册到导航路由

4.2 质量面板实现示例

以新增质量雷达面板为例,完整实现链路如下:

  1. 数据脚本(scripts/sync_quality_metrics.py):
# 生成模拟质量数据 metrics = { "completion_rate": random.randint(85, 98), "rejection_rate": random.randint(2, 15), "avg_duration": random.randint(30, 120) } Path("data/quality.json").write_text(json.dumps(metrics))
  1. 后端接口(dashboard/server.py):
@app.get("/api/quality") def get_quality(): file = Path("data/quality.json") if not file.exists(): return {"error": "Data not ready"} return JSONResponse(json.loads(file.read_text()))
  1. 前端组件(edict/frontend/src/components/QualityRadar.tsx):
const QualityRadar = () => { const [metrics, setMetrics] = useState<QualityMetrics>(); useEffect(() => { fetchQualityMetrics().then(setMetrics); }, []); return ( <div className="quality-panel"> <RadarChart data={transformForChart(metrics)} /> <MetricTable data={metrics} /> </div> ); };

5. Agent扩展体系

5.1 Agent定义规范

每个Agent必须包含完整的SOUL.md定义:

# 审计司 (Audit Office) ## 职责 - 结果合规性检查 - 风险识别与评估 - 质量审计报告生成 ## 输入规范 - 任务执行结果JSON - 相关附件清单 - 执行上下文信息 ## 输出规范 - 审计报告MD格式 - 问题清单 - 整改建议 ## 权限范围 - 可读取所有任务数据 - 可生成审计标记 - 不可修改原始结果

5.2 权限矩阵配置

在config/agents.py中维护权限矩阵:

AGENT_PERM_MATRIX = { "audit_office": { "read": ["*"], "write": ["audit_mark"], "deny": ["result_edit"] } }

6. 调度与Worker扩展

6.1 异常处理策略

实现三级故障处理机制:

  1. 重试策略:
def retry_policy(failure_count: int) -> bool: return failure_count < 3 # 最多重试3次
  1. 升级策略:
def escalate_policy(wait_seconds: int) -> bool: return wait_seconds > 300 # 5分钟未处理则升级
  1. 回滚策略:
def rollback(task: Task) -> bool: return ( task.state == "QA" and task.duration > timedelta(hours=2) ) # QA阶段超过2小时则回滚

6.2 调度器实现

基于Redis Streams的分布式调度器:

class TaskScheduler: def __init__(self, redis: Redis): self.redis = redis self.stream = "edict:tasks" async def schedule(self, task: Task): await self.redis.xadd(self.stream, task.dict()) async def consume(self): while True: messages = await self.redis.xreadgroup( "edict_workers", "worker1", {self.stream: ">"}, count=1 ) if messages: await process_message(messages[0])

7. PyQt启动器实现

7.1 架构设计

启动器采用经典MVC模式:

edict_launcher.py # 入口文件 edict_pyqt_ui.py # 主界面(View) service_controller.py # 服务控制(Controller) config_manager.py # 配置管理(Model)

7.2 核心功能实现

  1. ��务控制:
class ServiceController: def start(self): if self._check_port(): raise RuntimeError("Port already in use") self._process = subprocess.Popen( ["python", "dashboard/server.py"], stdout=subprocess.PIPE, stderr=subprocess.STDOUT ) self._start_output_thread() def _start_output_thread(self): def read_output(): while self._process.poll() is None: line = self._process.stdout.readline() self.sig_output.emit(line.decode()) Thread(target=read_output, daemon=True).start()
  1. 日志展示:
class LogViewer(QTextEdit): def __init__(self): super().__init__() self.setReadOnly(True) self.setFont(QFont("Consolas", 10)) def append_log(self, text: str): self.moveCursor(QTextCursor.End) self.insertPlainText(text) self.ensureCursorVisible()

8. 数据兼容与迁移

8.1 兼容层设计

对于历史数据,实现智能兼容层:

def normalize_task(raw: dict) -> Task: """将不同版本的任务数据标准化""" return Task( id=raw.get("id") or raw["task_id"], title=raw["title"], state=normalize_state(raw["state"]), created_at=parse_date(raw) ) def parse_date(raw: dict) -> datetime: """兼容多种日期格式""" if isinstance(raw["created_at"], datetime): return raw["created_at"] return datetime.strptime(raw["created_at"], "%Y-%m-%dT%H:%M:%S")

8.2 迁移脚本示例

数据库变更迁移脚本:

def migrate_qa_state(): """将历史任务中的Review状态拆分为QA和Review""" with Session() as session: tasks = session.query(Task).filter_by(state="Review").all() for task in tasks: if needs_qa(task): # 根据业务规则判断 task.state = "QA" session.commit()

9. 测试与发布流程

9.1 测试金字塔实现

  1. 单元测试:
def test_state_transition(): assert validate_transition("Doing", "QA") assert not validate_transition("Done", "Doing")
  1. 集成测试:
def test_task_flow(): task = create_task() assert task.state == "Taizi" move_to_state(task, "Zhongshu") assert task.state == "Zhongshu"
  1. E2E测试:
def test_create_task_ui(): browser = Chrome() browser.visit("/") browser.click("New Task") browser.fill("title", "Test Task") browser.click("Submit") assert browser.has_text("Test Task")

9.2 发布检查清单

  1. [ ] 所有测试通过
  2. [ ] 数据库迁移脚本验证
  3. [ ] 版本号更新
  4. [ ] 文档更新
  5. [ ] 回滚方案准备
  6. [ ] 监控指标配置

10. 运维与安全实践

10.1 配置管理

采用分层配置策略:

# config.py class Config: def __init__(self): self._config = { **self._load_defaults(), **self._load_env(), **self._load_secrets() } def _load_secrets(self): return dotenv_values(".env.secret")

10.2 安全实践

  1. 密钥管理:

    • 禁止硬编码密钥
    • 使用环境变量或密钥管理服务
    • 桌面启动器中的密钥输入做内存级处理
  2. 日志规范:

    • 敏感信息脱敏
    • 统一日志格式
    • 按服务拆分日志文件
  3. 监控指标:

    • 服务存活状态
    • 任务积压数量
    • 异常发生频率
    • 资源使用情况

11. 工程化改造路线图

建议按照以下阶段逐步推进:

  1. 基础设施阶段(1-2周)

    • 统一配置管理
    • 建立CI流水线
    • 实现基础监控
  2. 核心能力阶段(2-3周)

    • 完善状态机实现
    • 构建调度系统
    • 实现基础测试套件
  3. 扩展能力阶段(3-4周)

    • 新增业务面板
    • 扩展Agent类型
    • 增强桌面启动器
  4. 治理能力阶段(持续迭代)

    • 完善文档体系
    • 建立发布规范
    • 优化运维流程

在实际操作中,我发现最有效的改造方式是"小步快跑"——每个迭代周期控制在1-2周,每次聚焦一个明确的改进目标。例如先集中精力完善状态机和工作流,再转向UI增强和工具链优化。这种渐进式改造既保证了系统持续可用,又能稳步提升工程化水平。

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进