Files
jcl-cobol-data-create/agent/prompt_builder.py
T
2026-07-12 14:54:50 +08:00

147 lines
6.4 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
from typing import List
from agent.models import ProgramMeta
class PromptBuilder:
"""将解析后的程序元数据和规则组装成 API prompt。"""
def build(self, meta: ProgramMeta, rules_text: str,
group_descriptions: List[str], group_count: int) -> str:
"""构建完整的 API prompt。"""
parts = []
parts.append(self._build_basic_info(meta))
parts.append(self._build_process_detail(meta))
parts.append(self._build_input_structures(meta))
parts.append(self._build_output_records(meta))
parts.append(rules_text)
parts.append(self._build_output_format(meta))
parts.append(self._build_generation_instruction(
group_descriptions, group_count, meta.input_type
))
return '\n\n'.join(parts)
def _build_basic_info(self, meta: ProgramMeta) -> str:
lines = [
f"## プログラム基本情報",
f"- システム名: {meta.system_name}",
f"- プログラムID: {meta.program_id}",
f"- プログラム名: {meta.program_name}",
f"- PGMパターン: {meta.pgm_pattern}",
f"- 入力タイプ: {self._input_type_label(meta.input_type)}",
]
if meta.summary_lines:
lines.append(f"- 機能概要: {' '.join(meta.summary_lines)}")
return '\n'.join(lines)
def _build_process_detail(self, meta: ProgramMeta) -> str:
return f"## 処理詳細\n\n```\n{meta.process_detail}\n```"
def _build_input_structures(self, meta: ProgramMeta) -> str:
parts = ["## 入力構造"]
input_files = [f for f in meta.files if 'I' in f.io]
for f in input_files:
parts.append(f"### ファイル {f.identifier} (DD名: {f.dd_name}, COPY: {f.copy_group}, 媒体: {f.medium})")
fields = meta.copy_fields.get(f.identifier, [])
if fields:
parts.append("| 項目名 | PIC | バイト数 |")
parts.append("|--------|-----|----------|")
for cf in fields:
parts.append(f"| {cf.name} | {cf.pic_type} | {cf.pic_bytes} |")
else:
parts.append("(構造情報なし)")
db_inputs = [f for f in meta.files if 'I' in f.io and f.medium == 'DB']
if db_inputs or meta.db_tables:
parts.append("### DBテーブル構造")
for table_name, table in meta.db_tables.items():
parts.append(f"**表名: {table_name}**")
pk_str = ', '.join(table.pk_columns)
parts.append(f"主キー: {pk_str}")
parts.append("| 項目名 | 英字名 | タイプ | 最大長 | KEY |")
parts.append("|--------|--------|--------|--------|-----|")
for col in table.columns:
key_mark = '✓' if col.is_pk else ''
parts.append(f"| {col.name_jp} | {col.name_en} | {col.type} | {col.max_len} | {key_mark} |")
return '\n\n'.join(parts)
def _build_output_records(self, meta: ProgramMeta) -> str:
return f"## 出力レコード定義\n\n```\n{meta.output_records}\n```"
def _build_output_format(self, meta: ProgramMeta) -> str:
lines = [
"## 出力形式",
"",
"### JSON形式(ファイル入力の場合)",
"",
"JSON構造:",
"```json",
"{",
' "program": "{プログラムID}",',
' "records": [',
' { "input": { "FD名": { "項目名": "値", ... } } },',
' ...',
' ]',
"}",
"```",
"",
"### 項目値のルール(PIC → JSON値)",
"| PIC | JSON内表示 | 例 |",
"|-----|-----------|-----|",
"| PIC X(n) | 左詰め + スペース埋め | `\"A0000001\"` |",
"| PIC 9(n) | 右詰め + 先行ゼロ | `\"00000101\"` |",
"| PIC S9(n) | 符号 + 右詰め + 先行ゼロ | `\"+0000101\"` |",
"| PIC S9(n)V9(m) | 符号 + 右詰め + 小数点含む | `\"+001234567\"` |",
"| PIC S9(n) COMP | 通常の10進数文字列 | `\"300\"` |",
"| PIC S9(n) COMP-3 | 通常の10進数文字列 | `\"1234\"` |",
"| PIC 9(n) COMP-3 | 通常の10進数文字列 | `\"1234\"` |",
"| FILLER(純粋予約) | グループIDとレコード番号を含むパターン | `\"D000000...001\"` |",
"| FILLER(業務予約) | 全スペース(PIC X) または 全ゼロ(PIC 9) | |",
"",
"### SQL形式(DB入力の場合)",
"各グループ1つのSQLファイル: `{program}_g{groupId}.sql`",
"",
"SQL例:",
"```sql",
"-- Group: 1",
"INSERT INTO TABLE_NAME (COL1, COL2) VALUES",
"('val1', 'val2');",
"```",
"",
"### データ生成の注意",
"- 項目名に意味がある場合(DATE→日付、NAME→氏名)、実際の形式に合った値を生成すること",
"- 隣接するレコード間で、同じ項目に異なる値を設定すること",
]
return '\n'.join(lines)
def _build_generation_instruction(self, descriptions: List[str],
count: int, input_type: str) -> str:
lines = [
"## 生成指示",
f"生成するグループ数: {count}",
"各グループの内容:",
]
for i, desc in enumerate(descriptions, 1):
lines.append(f" - g{i}: {desc}")
if input_type == 'file':
lines.append("出力: JSONファイル(1グループ=1JSONファイル)")
elif input_type == 'db':
lines.append("出力: SQL INSERTファイル(1グループ=1SQLファイル)")
else:
lines.append("出力: JSONファイル + SQL INSERTファイル")
lines.append("")
lines.append("応答形式: JSONで返してください。最上位キー \"groups\" を使い、各グループを \"g1\", \"g2\" ... とします。")
lines.append("例: {\"groups\": {\"g1\": {\"program\": \"XXX\", \"records\": [...]}, \"g2\": {...}}}")
return '\n'.join(lines)
@staticmethod
def _input_type_label(t: str) -> str:
labels = {'file': 'ファイル', 'db': 'DB', 'mixed': '混合(ファイル+DB'}
return labels.get(t, t)