找回密码
 立即注册
首页 业界区 安全 标书智能体(二)——生成标书提纲代码+提示词 ...

标书智能体(二)——生成标书提纲代码+提示词

汤流婉 4 小时前
用Python+React打造一个开源的AI写标书智能体~
完整代码已开源
代码很多,文章只放主要代码和提示词,完整代码可以查看开源项目
Github: https://github.com/yibiaoai/yibiao-simple
Gitee: https://gitee.com/yibiao-ai/yibiao-simple
今天是第二期,根据解析好的项目概述和技术评分需求,生成投标文件提纲:
1.png

2.png

一份好的标书,提纲是关键,而生成好的提纲,则有以下几个难点:

  • 格式化输出:为了生成正文时,AI能够很好的理解提纲,保证结构不错乱,那么提纲必须是格式化的
  • 超出AI输出长度:几十万字的标书,提纲也不会短,现在AI虽然都号称几十万的上下文,但实际输出也就2千字左右,无法直接完整的长提纲
  • 提纲可编辑:虽然AI能生成比较不错的提纲,但还是没法100%满足要求,所以提纲必须是可编辑的,而且编辑后还不能破坏原有的结构
下面,咱们就来逐项分析一下,如何解决上述难点。
一、短标书+能力较强的AI模型

当生成的标书长度要求不高,比如三五万字。且AI能输出的token数比较长,如最新的 glm-4.5  和 doubao-seed-1-6,大约可以直接输出8000字左右,那么就可以使用下面这种简单的结构。
JSON结构
  1. {
  2.   "outline": [
  3.     {
  4.       "id": "1",
  5.       "title": "",
  6.       "description": "",
  7.       "children": [
  8.         {
  9.           "id": "1.1",
  10.           "title": "",
  11.           "description": "",
  12.           "children":[
  13.               {
  14.                 "id": "1.1.1",
  15.                 "title": "",
  16.                 "description": ""
  17.               }
  18.           ]
  19.         }
  20.       ]
  21.     }
  22.   ]
  23. }
复制代码
提示词

SystemPrompt
  1. 你是一个专业的标书编写专家。根据提供的项目概述和技术评分要求,生成投标文件中技术标部分的目录结构。要求:1. 目录结构要全面覆盖技术标的所有必要章节2. 章节名称要专业、准确,符合投标文件规范3. 一级目录名称要与技术评分要求中的章节名称一致,如果技术评分要求中没有章节名称,则结合技术评分要求中的内容,生成一级目录名称4. 一共包括三级目录5. 返回标准JSON格式,包含章节编号、标题、描述和子章节6. 除了JSON结果外,不要输出任何其他内容JSON格式要求:{
  2.   "outline": [
  3.     {
  4.       "id": "1",
  5.       "title": "",
  6.       "description": "",
  7.       "children": [
  8.         {
  9.           "id": "1.1",
  10.           "title": "",
  11.           "description": "",
  12.           "children":[
  13.               {
  14.                 "id": "1.1.1",
  15.                 "title": "",
  16.                 "description": ""
  17.               }
  18.           ]
  19.         }
  20.       ]
  21.     }
  22.   ]
  23. }
复制代码
UserPrompt
  1. 请基于以下项目信息生成标书目录结构:
  2. 项目概述:
  3. {overview}
  4. 技术评分要求:
  5. {requirements}
  6. 请生成完整的技术标目录结构,确保覆盖所有技术评分要点。
复制代码
二、长标书+普通AI模型

要想使用如 glm-4-air 这样低价的普通模型,也能生成几十万字标书需要的长提纲,那实现起来就复杂多了。
限制

  • 上下文短,仅能输出1500字左右
  • 输出结果不稳定,尤其是json这类结构化数据,可能出现格式错误
思路

  • 先生成一级目录(要与技术评分要求一一对应)
  • 遍历一级目录,逐个生成二、三级目录(多个AI任务并发生成,要保证每个任务生成的目录和其他任务的不重复)
  • 校验生成的json格式是否标准
  • 最后拼成完整的目录
这种生成工作流,理论上可以生成无限长度的提纲。
生成一级标题

SystemPrompt
  1. ### 角色
  2. 你是专业的标书编写专家,擅长根据项目需求编写标书。
  3. ### 人物
  4. 1. 根据得到的项目概述(overview)和评分要求(requirements),撰写技术标部分的一级提纲
  5. ### 说明
  6. 2. 只设计一级标题,数量要和"评分要求"一一对应
  7. 3. 一级标题名称要进行简单修改,不能完全使用"评分要求"中的文字
  8. ### Output Format in JSON
  9. {
  10.         "rating_item":"原评分项",
  11.         "new_title":"根据评分项修改的标题"
  12. }
复制代码
UserPrompt
  1. ### 项目信息
  2. <overview>
  3. {overview}
  4. </overview>
  5. <requirements>
  6. {requirements}
  7. </requirements>
  8. 直接返回json,不要任何额外说明或格式标记
复制代码
生成二级标题

为了生成结果稳定,我们不让AI来处理json框架,而是提前用代码拼接好json框架,仅让AI在json框架中填写内容
拼接json框架
我这里额外加了一个nodes_distribution,是为了让二三级目录数量不一样,随机了两个重点章节,这样更符合实际情况,这个不重要,感兴趣可以直接查看源码。
下面的代码是拼接json框架的:
  1. def generate_one_outline_json_by_level1(level1_title: str, level1_index: int, nodes_distribution: Dict) -> Dict:
  2.     # 获取当前一级节点下的二级节点数量和叶子节点分配
  3.     level2_count = nodes_distribution['level2_nodes'][level1_index - 1]
  4.     leaf_distribution = nodes_distribution['leaf_per_level2'][level1_index - 1]
  5.    
  6.     # 创建一级节点
  7.     level1_node = {
  8.         "id":f"{level1_index}",
  9.         "title": level1_title,
  10.         "description": "",
  11.         "children": []
  12.     }
  13.    
  14.     # 创建二级节点
  15.     for j in range(level2_count):
  16.         level2_node = {
  17.             "id":f"{level1_index}.{j+1}",
  18.             "title": "",  # 二级标题留空
  19.             "description": "",
  20.             "children": []
  21.         }
  22.         
  23.         # 创建三级节点(叶子节点)
  24.         leaf_count = leaf_distribution[j]
  25.         for k in range(leaf_count):
  26.             level2_node["children"].append({
  27.                 "id":f"{level1_index}.{j+1}.{k+1}",
  28.                 "title": "",  # 三级标题留空
  29.                 "description": ""
  30.             })
  31.         
  32.         level1_node["children"].append(level2_node)
  33.    
  34.     return level1_node
复制代码
拼接其他章节的标题,需要传给AI参考,以免生成重复的章节内容
  1. other_outline = "\n".join([f"{j+1}. {node['new_title']}"
  2.                     for j, node in enumerate(level_l1)
  3.                     if j!= i])
复制代码
SystemPrompt
json_outline是前面生成的json框架
  1. ### 角色
  2. 你是专业的标书编写专家,擅长根据项目需求编写标书。
  3. ### 任务
  4. 1. 根据得到项目概述(overview)、评分要求(requirements)补全标书的提纲的二三级目录
  5. ### 说明
  6. 2. 你将会得到一段json,这是提纲的其中一个章节,你需要再原结构上补全标题(title)和描述(description)
  7. 3. 二级标题根据一级标题撰写,三级标题根据二级标题撰写
  8. 4. 补全的内容要参考项目概述(overview)、评分要求(requirements)等项目信息
  9. 5. 你还会收到其他章节的标题(other_outline),你需要确保本章节的内容不会包含其他章节的内容
  10. ### 注意事项
  11. 在原json上补全信息,禁止修改json结构,禁止修改一级标题
  12. ### Output Format in JSON
  13. {json_outline}
复制代码
UserPrompt
  1. ### 项目信息
  2. <overview>
  3. {overview}
  4. </overview>
  5. <requirements>
  6. {requirements}
  7. </requirements>
  8. <other_outline>
  9. {other_outline}
  10. </other_outline>
  11. 直接返回json,不要任何额外说明或格式标记
复制代码
校验生成json结果是否和传入框架一致
  1. import json
  2. def check_json(json_str: str, schema: str | dict) -> tuple[bool, str]:
  3.     """
  4.     根据模板 JSON 校验目标字符串的格式是否符合要求
  5.    
  6.     Args:
  7.         json_str: 要校验的 JSON 字符串
  8.         schema: 模板 JSON 字符串或字典对象,用于定义预期的数据结构
  9.         
  10.     Returns:
  11.         tuple[bool, str]: (是否验证通过, 错误信息)
  12.         如果验证通过返回 (True, ""),否则返回 (False, 错误原因)
  13.     """
  14.     try:
  15.         # 解析输入的 JSON 字符串
  16.         try:
  17.             data = json.loads(json_str)
  18.         except json.JSONDecodeError as e:
  19.             return False, f"JSON 解析错误: {str(e)}"
  20.         
  21.         # 处理 schema 参数
  22.         try:
  23.             if isinstance(schema, str):
  24.                 schema = json.loads(schema)
  25.             elif not isinstance(schema, dict):
  26.                 return False, "schema 必须是 JSON 字符串或字典对象"
  27.         except json.JSONDecodeError as e:
  28.             return False, f"schema 解析错误: {str(e)}"
  29.         
  30.         def check_structure(target, template, path=""):
  31.             # 处理数字类型(int 和 float 可以互换)
  32.             if isinstance(template, (int, float)) and isinstance(target, (int, float)):
  33.                 return True, ""
  34.                
  35.             # 检查基本数据类型
  36.             if type(template) != type(target) and not (isinstance(template, (int, float)) and isinstance(target, (int, float))):
  37.                 return False, f"路径 '{path}' 的类型不匹配: 期望 {type(template).__name__}, 实际 {type(target).__name__}"
  38.                
  39.             # 如果是列表类型
  40.             if isinstance(template, list):
  41.                 if not template:  # 如果模板列表为空,则允许任何列表
  42.                     return True, ""
  43.                 if not target:  # 如果目标列表为空,但模板不为空
  44.                     return False, f"路径 '{path}' 的列表为空,但期望有内容"
  45.                     
  46.                 # 检查列表中的每个元素是否符合模板中第一个元素的格式
  47.                 template_item = template[0]
  48.                 for i, item in enumerate(target):
  49.                     is_valid, error = check_structure(item, template_item, f"{path}[{i}]")
  50.                     if not is_valid:
  51.                         return False, error
  52.                 return True, ""
  53.                
  54.             # 如果是字典类型
  55.             elif isinstance(template, dict):
  56.                 # 检查所有必需的键是否存在,并且值的类型是否正确
  57.                 for key in template:
  58.                     if key not in target:
  59.                         return False, f"路径 '{path}' 缺少必需的键 '{key}'"
  60.                     is_valid, error = check_structure(target[key], template[key], f"{path}.{key}")
  61.                     if not is_valid:
  62.                         return False, error
  63.                 return True, ""
  64.                
  65.             # 对于其他基本类型,返回 True
  66.             return True, ""
  67.                
  68.         is_valid, error = check_structure(data, schema)
  69.         return is_valid, error if not is_valid else ""
  70.         
  71.     except Exception as e:
  72.         return False, f"未预期的错误: {str(e)}"
复制代码
在执行过程中,设置3次重试,如果校验没通过,再重新执行一次,以保证成功率
3.png

完整代码已开源

Github: https://github.com/yibiaoai/yibiao-simple
Gitee: https://gitee.com/yibiao-ai/yibiao-simple

来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

相关推荐

您需要登录后才可以回帖 登录 | 立即注册