agent开发-日志agent开发日志 day4

这一篇是整个系统中最核心的文件

这个方法是调取llm,然后把llm返回的产品经理需求内容抠出来,转换成json格式,并且进行Pydantic校验,判断是模型类还是list列表,然后接下来采用不同的方法

点击查看代码
def _invoke_and_parse(llm, messages, schema) -> Any:
    """
    调 LLM → 从 raw text 提取 JSON → Pydantic 校验 → 返回 Python 对象
    ────────────────────────────────────────────────────────────
    参数:
      llm      - ChatOpenAI 实例(未经 structured_output 绑定)
      messages - [SystemMessage, HumanMessage] 列表
      schema   - Pydantic BaseModel 子类 或 list[BaseModel] 泛型

    返回:
      校验后的 Pydantic 对象(如 Requirement)或对象列表(如 list[DevTask])

    异常:
      ValueError — JSON 解析失败或 Schema 校验失败
    """
    # ① 调 LLM,拿到 raw text
    response = llm.invoke(messages)
    raw_text = response.content if hasattr(response, "content") else str(response)

    # ② 从 raw text 里提取 JSON 片段
    json_str = _extract_json_from_text(raw_text)

    # ③ Pydantic 校验
    try:
        # 判断是模型类还是 list 泛型
        if isinstance(schema, type) and issubclass(schema, BaseModel):
            return schema.model_validate_json(json_str)
        else:
            # list[DevTask] 等泛型,用 TypeAdapter
            return TypeAdapter(schema).validate_json(json_str)
    except Exception as parse_error:
        # 校验失败 — 把原始 LLM 输出也带上,方便调试
        raise ValueError(
            f"JSON 解析失败: {parse_error}\n"
            f"LLM 原始输出(前500字):\n{raw_text[:500]}"
        )

这一段是检查产品经理的需求,然后把ai生成的转化为json,拼接进HumanMessage ,在调用llm解析进行任务拆解

点击查看代码
# =============================================================================
# 节点2:任务拆解器
# =============================================================================

def breakdown_tasks_node(state: AgentState) -> dict[str, Any]:
    """
    第二步"拆解开发任务"对应的节点函数
    ──────────────────────────────────
    调用时机:节点1完成后自动触发
    前置条件:state.requirement 必须非空
    依赖:state.requirement + state.task_count
    产出:一个 list[DevTask],写回 state.tasks
    副作用:state.current_stage 从 "breakdown" 变为 "review"
    """
    # 前置条件检查
    if state.requirement is None:
        return {
            "error_message": "任务拆解失败:缺少前置需求(requirement 为空)",
            "current_stage": "error",
        }

    try:
        llm = get_llm()

        requirement_json = state.requirement.model_dump_json(indent=2)
        messages = [
            SystemMessage(content=BREAKDOWN_TASKS_SYSTEM),
            HumanMessage(content=build_task_breakdown_user_message(
                requirement_json=requirement_json,
                task_count=state.task_count,
            )),
        ]

        # 调 LLM → 提取 JSON 数组 → 校验为 list[DevTask]
        tasks = _invoke_and_parse(llm, messages, list[DevTask])

        return {
            "tasks": tasks,
            "current_stage": "review",
        }
    except Exception as e:
        return {
            "error_message": f"任务拆解失败: {e}",
            "current_stage": "error",
        }

最后这个方法就是根据前面的生成日志了还是先做验证,解析json,然后调用大模型生成

点击查看代码
# =============================================================================
# 节点3:日志生成
# =============================================================================

def generate_log_node(state: AgentState) -> dict[str, Any]:
    """
    第三步"生成每日工作日志"对应的节点函数
    ────────────────────────────────────────
    调用时机:用户在前端点击"一键生成今日日志"按钮
    前置条件:state.requirement 和 state.tasks 都必须非空
    依赖:state.requirement + state.tasks + state.task_marks
    产出:一个 DailyLog 对象,写回 state.daily_log
    副作用:state.current_stage 从 "review" 变为 "done"
    """
    if state.requirement is None:
        return {
            "error_message": "日志生成失败:缺少前置需求(requirement 为空)",
            "current_stage": "error",
        }
    if not state.tasks:
        return {
            "error_message": "日志生成失败:缺少开发任务列表(tasks 为空)",
            "current_stage": "error",
        }

    try:
        llm = get_llm()

        # 序列化 requirement 为 JSON
        requirement_json = state.requirement.model_dump_json(indent=2)

        # 构造任务列表数据(移除 task_id 减少噪声)
        tasks_for_prompt = []
        for t in state.tasks:
            d = t.model_dump()
            d.pop("task_id", None)
            tasks_for_prompt.append(d)
        tasks_json = json.dumps(tasks_for_prompt, ensure_ascii=False, indent=2)

        # 完成状态标记
        marks_for_prompt = [m.model_dump() for m in state.task_marks]
        marks_json = json.dumps(marks_for_prompt, ensure_ascii=False, indent=2)

        messages = [
            SystemMessage(content=GENERATE_LOG_SYSTEM),
            HumanMessage(content=build_log_generation_user_message(
                requirement_json=requirement_json,
                tasks_json=tasks_json,
                marks_json=marks_json,
            )),
        ]

        # 调 LLM → 提取 JSON → 校验为 DailyLog 对象
        daily_log = _invoke_and_parse(llm, messages, DailyLog)

        # --- 后处理:用代码覆盖 LLM 可能编造的字段 ---
        # 1. 日期:用今天的真实日期覆盖 LLM 编造的日期
        # 2. source_task_ids:用实际的 task_id 列表覆盖(LLM 会编造不存在的ID)
        # model_copy(update={...}) 创建一个新对象,只改指定字段,其余保持 LLM 输出
        corrected = daily_log.model_copy(update={
            "date": datetime.date.today().isoformat(),
            "source_task_ids": [t.task_id for t in state.tasks],
        })

        return {
            "daily_log": corrected,
            "current_stage": "done",
        }
    except Exception as e:
        return {
            "error_message": f"日志生成失败: {e}",
            "current_stage": "error",
        }

posted @ 2026-05-23 10:53  marisa3  阅读(10)  评论(0)    收藏  举报