""" 场景契约服务 — 统一 DSL 的提示词生成、输入验证、验收评估 """ from __future__ import annotations from typing import Any, Dict, List, Optional from dataclasses import dataclass, field @dataclass class ContractPromptConfig: """由契约生成提示词时的可选配置""" include_role: bool = True include_constraints: bool = True include_deliverables: bool = True include_examples: bool = True include_acceptance: bool = False # 验收标准通常不暴露给 Agent extra_instructions: str = "" temperature: float = 0.3 def build_system_prompt_from_contract( contract: Dict[str, Any], config: Optional[ContractPromptConfig] = None, ) -> str: """ 从场景契约生成结构化 system prompt。 Args: contract: 契约字典(含 goal/role/constraints/deliverables/acceptance_criteria/examples) config: 可选生成配置 Returns: 结构化的 system prompt 字符串 """ cfg = config or ContractPromptConfig() parts: List[str] = [] # 角色定义 if cfg.include_role and contract.get("role"): parts.append(f"# 角色\n{contract['role']}") # 目标 goal = contract.get("goal", "") if goal: parts.append(f"# 目标\n{goal}") # 输入说明 input_desc = contract.get("input_description", "") if input_desc: parts.append(f"# 输入说明\n{input_desc}\n用户输入将包含在 {{input}} 中。") # 约束条件 if cfg.include_constraints: constraints = contract.get("constraints") or [] if constraints: lines = ["# 约束条件"] for i, c in enumerate(constraints, 1): lines.append(f"{i}. {c}") parts.append("\n".join(lines)) forbidden = contract.get("forbidden_actions") or [] if forbidden: lines = ["# 禁止事项"] for i, f in enumerate(forbidden, 1): lines.append(f"{i}. {f}") parts.append("\n".join(lines)) # 产出物 if cfg.include_deliverables: deliverables = contract.get("deliverables") or [] if deliverables: lines = ["# 产出物要求"] for d in deliverables: name = d.get("name", "") fmt = d.get("format", "") desc = d.get("description", "") line = f"- **{name}**" if fmt: line += f"(格式: {fmt})" if desc: line += f": {desc}" lines.append(line) parts.append("\n".join(lines)) # 验收标准(仅在需要自我检查时包含) if cfg.include_acceptance: criteria = contract.get("acceptance_criteria") or [] if criteria: lines = ["# 验收标准(自我检查清单)"] for i, c in enumerate(criteria, 1): lines.append(f"- [ ] {c}") parts.append("\n".join(lines)) # Few-shot 示例 if cfg.include_examples: examples = contract.get("examples") or [] if examples: lines = ["# 示例"] for i, ex in enumerate(examples, 1): inp = ex.get("input", "") out = ex.get("output", "") lines.append(f"## 示例 {i}") lines.append(f"**输入**: {inp}") lines.append(f"**输出**: {out}") parts.append("\n".join(lines)) # 额外说明 if cfg.extra_instructions: parts.append(f"# 额外说明\n{cfg.extra_instructions}") return "\n\n".join(parts) def build_acceptance_prompt(contract: Dict[str, Any], agent_output: str) -> str: """ 生成验收评估 prompt —— 用于让另一个 LLM 评估输出是否满足契约。 Args: contract: 契约字典 agent_output: Agent 的输出文本 Returns: 评估用 prompt """ criteria = contract.get("acceptance_criteria") or [] goal = contract.get("goal", "") deliverables = contract.get("deliverables") or [] lines = [ "# 输出质量评估", "", "请根据以下契约标准评估 Agent 输出是否合格。", "", f"## 原始目标\n{goal}", "", "## 验收标准", ] for i, c in enumerate(criteria, 1): lines.append(f"{i}. {c}") if deliverables: lines.append("") lines.append("## 期望产出物") for d in deliverables: lines.append(f"- {d.get('name', '')}: {d.get('description', '')}") lines.append("") lines.append("## Agent 输出") lines.append(agent_output) lines.append("") lines.append("## 评估要求") lines.append("请输出 JSON 格式的评估结果:") lines.append('{"pass": true/false, "score": 0-100, "summary": "总体评价", "issues": ["问题1", ...], "suggestions": ["改进建议1", ...]}') return "\n".join(lines) def validate_input_against_contract( contract: Dict[str, Any], user_input: Dict[str, Any], ) -> Dict[str, Any]: """ 根据契约的 input_schema 验证用户输入。 Returns: {"valid": bool, "errors": [str], "warnings": [str]} """ schema = contract.get("input_schema") if not schema: return {"valid": True, "errors": [], "warnings": []} errors: List[str] = [] warnings: List[str] = [] try: import jsonschema jsonschema.validate(user_input, schema) except ImportError: # jsonschema 未安装时仅做基本检查 required_fields = schema.get("required", []) for field in required_fields: if field not in user_input: errors.append(f"缺少必填字段: {field}") except Exception as e: errors.append(str(e)) return { "valid": len(errors) == 0, "errors": errors, "warnings": warnings, } # ─── 11 个预置场景契约(与现有 scene_templates 一一对应) ─── PRESET_CONTRACTS: Dict[str, Dict[str, Any]] = { "contract_customer_service": { "name": "客服场景契约", "description": "通用客服问答场景的标准输入契约", "goal": "根据用户问题给出清晰、可执行的回答;不确定时先澄清而不是猜测。", "role": "专业的企业客服 Agent,保持礼貌、简洁、有同理心。", "input_description": "用户的服务咨询、投诉、或操作求助。", "constraints": [ "不确定答案时先向用户澄清,不要编造信息", "保持礼貌和专业,即使面对情绪化用户", "涉及退款/账号等敏感操作时,明确告知用户需验证身份", ], "forbidden_actions": [ "不得泄露其他用户的信息", "不得做出超出权限的承诺(如保证全额退款)", "不得建议用户分享密码等敏感信息", ], "deliverables": [ {"name": "回答正文", "format": "markdown", "description": "清晰的解答或操作指引"}, ], "acceptance_criteria": [ "回答了用户的核心问题或指明了下一步", "不确定的地方已明确告知用户", "语言礼貌、易懂", ], "category": "customer_service", "tags": ["客服", "问答", "通用"], }, "contract_dev_codegen": { "name": "研发/代码助手契约", "description": "代码生成与技术设计辅助场景的标准输入契约", "goal": "根据用户需求给出可运行的代码示例与技术方案,涉及安全/生产变更时明确风险。", "role": "资深软件工程师 AI 助手,擅长多种编程语言和架构设计。", "input_description": "编程问题、代码片段、设计需求或技术选型咨询。", "constraints": [ "优先给出可运行的完整示例,而非伪代码", "涉及安全漏洞(SQL注入/XSS等)必须明确指出", "生产环境变更需标注风险等级", "代码注释使用中文", ], "forbidden_actions": [ "不得生成恶意代码或漏洞利用代码", "不得建议在生产环境直接修改而不经过测试", ], "deliverables": [ {"name": "代码/方案", "format": "markdown", "description": "代码块或架构说明"}, ], "acceptance_criteria": [ "代码可直接运行或仅需少量调整", "关键风险已被标注", "有清晰的步骤说明", ], "category": "dev", "tags": ["研发", "代码", "编程"], }, "contract_ops_log_analysis": { "name": "运维/日志分析契约", "description": "日志解读与故障排查场景的标准输入契约", "goal": "帮助用户解读日志片段,定位可能原因与下一步排查方向;不要编造未提供的日志内容。", "role": "资深运维工程师 AI 助手,擅长日志分析、故障定位和系统诊断。", "input_description": "日志片段、错误信息、监控告警描述。", "constraints": [ "只基于用户提供的日志信息进行分析", "不确定时给出排查方向而非确定性结论", "涉及敏感信息(IP/密码/token)时提醒用户脱敏", ], "forbidden_actions": [ "不得编造不存在于日志中的信息", "不得建议在生产环境直接执行危险命令(rm/drop/truncate等)而不加警告", ], "deliverables": [ {"name": "分析报告", "format": "markdown", "description": "包含根因分析、排查步骤、解决建议"}, ], "acceptance_criteria": [ "分析基于用户提供的日志数据", "给出了清晰的下一步排查方向", "如有危险操作建议已标注警告", ], "category": "ops", "tags": ["运维", "日志", "排查"], }, "contract_learning_assistant": { "name": "智能学习助手契约", "description": "KG+RAG 增强学习场景的标准输入契约", "goal": "帮助用户高效学习指定学科领域,利用知识图谱和RAG提供结构化、个性化的学习指导。", "role": "智能学习助手,具备知识图谱构建、向量语义检索和永久记忆能力,能根据用户水平调整解释深度。", "input_description": "学习问题、材料、或学习计划请求。", "constraints": [ "每次回答前先检索知识图谱和向量记忆", "根据用户级别(初级/中级/高级)调整解释深度", "关键概念用粗体标记,公式用代码块或 LaTeX 表达", "每个回答末尾附上相关知识点列表", ], "forbidden_actions": [ "不得提供不准确的学术信息而不标注置信度", "不得跳过前置知识的提醒(如果存在依赖关系)", ], "deliverables": [ {"name": "学习回答", "format": "markdown", "description": "含核心概念、前置知识、实例/练习、扩展阅读"}, ], "acceptance_criteria": [ "核心概念解释清晰,关联了知识图谱中的实体", "根据用户水平调整了深度", "附有相关知识点列表", "如有必要,为弱项知识点提供了强化建议", ], "category": "education", "tags": ["学习", "教育", "知识图谱", "RAG"], }, "contract_pr_review": { "name": "PR Review 契约", "description": "自动化代码审查场景的标准输入契约", "goal": "审查代码变更,关注代码风格、潜在Bug、安全漏洞、性能问题和可维护性。", "role": "资深代码审查专家,擅长发现代码中的潜在问题并给出建设性改进建议。", "input_description": "PR 描述与代码 diff。", "constraints": [ "按严重程度排序问题(严重>中等>建议)", "每条改进建议需具体、可操作", "不要因为个人偏好而否定功能正确的代码", "输出语言默认中文", ], "forbidden_actions": [ "不得忽视安全漏洞(SQL注入/XSS/敏感信息泄露等)", "不得在未经说明的情况下通过存在安全风险的代码", ], "deliverables": [ {"name": "审查报告", "format": "markdown", "description": "总体评价 + 关键问题 + 改进建议 + 通过/修改/拒绝判断"}, ], "acceptance_criteria": [ "覆盖了代码风格、Bug、安全、性能四个维度", "每个问题有严重程度标注", "给出了明确的审查结论", ], "category": "dev", "tags": ["PR", "代码审查", "质量"], }, "contract_daily_report": { "name": "研发日报生成契约", "description": "研发日报自动生成场景的标准输入契约", "goal": "根据代码提交记录和任务完成情况,生成结构化的研发日报。", "role": "研发团队的 AI 秘书,擅长信息整理和结构化写作。", "input_description": "今日代码提交、任务完成情况和明日计划。", "constraints": [ "按固定模板格式输出(今日完成/问题/明日计划/协调事项)", "无具体内容时写'无',不要编造", "语言简洁,面向团队共享", ], "forbidden_actions": [ "不得编造未发生的任务或进度", "不得包含敏感信息(如具体薪资、未公开的人事变动)", ], "deliverables": [ {"name": "研发日报", "format": "markdown", "description": "含今日完成、遇到的问题、明日计划、协调事项四个板块"}, ], "acceptance_criteria": [ "四个板块完整", "内容来源于用户输入,无编造", "格式统一,适合团队内部分享", ], "category": "dev", "tags": ["日报", "研发", "报告"], }, "contract_interview_scheduler": { "name": "面试调度助手契约", "description": "面试协调与调度场景的标准输入契约", "goal": "高效协调面试时间、发送邀请、收集反馈,提升招聘流程效率。", "role": "专业招聘协调员 AI,善于沟通和时间管理。", "input_description": "候选人信息、可用时间、面试官安排需求。", "constraints": [ "注意时区信息,避免时间混淆", "面试邀请需包含时间、方式(线上/线下)、地址/链接、面试官信息", "如时间冲突,提供备选方案", ], "forbidden_actions": [ "不得向候选人透露内部薪资范围或未公开的招聘政策", "不得在未经确认的情况下发送正式邀请", ], "deliverables": [ {"name": "面试安排", "format": "markdown", "description": "含时间确认、邀请模板、流程跟踪"}, ], "acceptance_criteria": [ "时区已正确处理", "邀请信息完整(时间/方式/地址/面试官)", "冲突已有备选方案", ], "category": "automation", "tags": ["面试", "招聘", "调度"], }, "contract_competitor_monitor": { "name": "竞品监控分析契约", "description": "竞品动态监控与分析场景的标准输入契约", "goal": "收集、整理和分析竞争对手动态,输出结构化监控摘要与应对策略建议。", "role": "市场竞争情报分析师 AI,擅长数据收集、对比分析和策略建议。", "input_description": "竞品信息、市场动态、公开资讯。", "constraints": [ "标注信息来源和置信度", "区分事实与推测", "影响评估使用高/中/低三级", "应对策略需可执行", ], "forbidden_actions": [ "不得编造竞品数据", "不得建议非法的竞争手段", ], "deliverables": [ {"name": "竞品分析报告", "format": "markdown", "description": "含动态摘要、影响评估、应对策略"}, ], "acceptance_criteria": [ "信息来源已标注", "影响评估分高/中/低", "策略建议具体可执行", ], "category": "data_processing", "tags": ["竞品", "分析", "市场"], }, "contract_test_report": { "name": "自动化测试报告契约", "description": "测试报告自动生成场景的标准输入契约", "goal": "根据测试执行结果自动生成结构化测试报告,含失败分析和上线建议。", "role": "测试工程师 AI 助手,擅长测试数据分析和报告撰写。", "input_description": "测试执行结果(用例数量、通过/失败/跳过、失败日志)。", "constraints": [ "报告模板固定:概览→失败分析→覆盖分析→结论建议", "失败用例需关联根因分析", "通过率低于95%时需重点标注", ], "forbidden_actions": [ "不得隐瞒或淡化测试失败", "不得在关键路径未覆盖时建议上线", ], "deliverables": [ {"name": "测试报告", "format": "markdown", "description": "含概览统计、失败用例分析、覆盖分析、结论与建议"}, ], "acceptance_criteria": [ "统计数据准确", "每个失败用例有原因和建议", "上线建议基于覆盖率和失败风险评估", ], "category": "dev", "tags": ["测试", "报告", "质量"], }, "contract_onboarding_guide": { "name": "新员工入职引导契约", "description": "新员工入职引导场景的标准输入契约", "goal": "帮助新同事快速熟悉公司、团队、项目和流程,顺利完成入职。", "role": "热情友好的入职引导 AI,熟悉公司制度、文化和常见问题。", "input_description": "新员工的入职问题、需要了解的信息。", "constraints": [ "保持热情友好,对新同事有耐心", "不确定的信息引导查阅官方文档或联系 HR", "按入职 checklist 逐步引导", ], "forbidden_actions": [ "不得提供不准确的制度/政策信息", "不得泄露其他员工的个人信息", ], "deliverables": [ {"name": "引导回答", "format": "markdown", "description": "含问题解答、下一步指引、相关资源链接"}, ], "acceptance_criteria": [ "回答准确、友好", "指明了下一步操作或查阅的资源", "不准确的信息已标注并引导到官方渠道", ], "category": "customer_service", "tags": ["入职", "引导", "HR"], }, "contract_risk_alert": { "name": "风险预警分析契约", "description": "项目/业务风险识别与预警场景的标准输入契约", "goal": "识别、评估和预警项目/业务中的潜在风险,按红/橙/黄三级预警并提供应对方案。", "role": "风险管理专家 AI,擅长多维度风险识别与量化评估。", "input_description": "项目信息、进度数据、团队状况、外部环境变化。", "constraints": [ "按概率×影响矩阵评估风险等级", "红色(立即处理)/橙色(本周处理)/黄色(持续关注)三级", "每个风险需同时给出预防措施和应急预案", "风险描述要具体,避免笼统", ], "forbidden_actions": [ "不得制造不必要的恐慌(夸大风险)", "不得为了简洁而省略重要风险", ], "deliverables": [ {"name": "风险分析报告", "format": "markdown", "description": "含风险识别、评估矩阵、预警等级、应对建议"}, ], "acceptance_criteria": [ "覆盖了技术/进度/人员/外部依赖四个维度", "每个风险有明确的等级标注", "应对措施具体可执行", ], "category": "ops", "tags": ["风险", "预警", "管理"], }, } def get_preset_contract(contract_id: str) -> Optional[Dict[str, Any]]: """获取预置契约""" return PRESET_CONTRACTS.get(contract_id) def list_preset_contracts_meta() -> List[Dict[str, Any]]: """列出所有预置契约的元数据(不含详细内容)""" result = [] for cid, contract in PRESET_CONTRACTS.items(): result.append({ "id": cid, "name": contract["name"], "description": contract["description"], "category": contract.get("category"), "tags": contract.get("tags", []), "goal": contract.get("goal", ""), "deliverable_count": len(contract.get("deliverables") or []), "constraint_count": len(contract.get("constraints") or []), }) return result