feat: deepseek summary agent + clean old memory logs + merge prep

This commit is contained in:
sj
2026-08-09 09:04:27 +08:00
parent 7399b0bf14
commit 9c38f32d52
34 changed files with 98469 additions and 2378 deletions
+87 -12
View File
@@ -1,10 +1,10 @@
#!/home/xzq/miniconda3/envs/test4py311/bin/python
"""Scope-aware whole-job summary stage.
"""Scope-aware whole-job summary and DeepSeek report stage.
Summary is an objective result index and quality-control layer. It reads all
stage manifests in a job, groups them by scope_id, extracts key metrics and
artifacts, and writes machine-readable and human-readable summaries. It does
not perform deep biological interpretation.
The deterministic layer first builds a traceable manifest/artifact index. By
default that evidence is then passed to DeepSeek to produce the human-readable
Chinese report. The evidence index remains a separate artifact so generated
prose can always be audited against local results.
"""
import argparse
@@ -16,6 +16,10 @@ from pathlib import Path
from typing import Any, Dict, Iterable, List, Optional, Tuple
PROJECT_ROOT = Path(__file__).resolve().parents[2]
if str(PROJECT_ROOT) not in sys.path:
sys.path.insert(0, str(PROJECT_ROOT))
CONDA_BIN = "/home/xzq/miniconda3/envs/test4py311/bin"
if CONDA_BIN not in os.environ.get("PATH", ""):
os.environ["PATH"] = CONDA_BIN + ":" + os.environ.get("PATH", "")
@@ -256,6 +260,10 @@ def main():
parser.add_argument("--scope-id", help="optional explicit scope_id filter")
parser.add_argument("--force", action="store_true", help="overwrite existing results")
parser.add_argument("--log-file", help="log file path")
parser.add_argument("--no-deepseek", action="store_true", help="write only the deterministic evidence index")
parser.add_argument("--framework", help="optional Markdown framework for the DeepSeek report")
parser.add_argument("--deepseek-model", default="", help="optional DeepSeek model override")
parser.add_argument("--deepseek-max-tokens", type=int, default=16000)
args = parser.parse_args()
manifest_path = Path(args.manifest).expanduser().resolve() if args.manifest else None
@@ -284,11 +292,11 @@ def main():
artifact_rows = [row for item in summaries for row in item["artifact_rows"]]
checks = build_checks(summaries)
report = final_dir / f"{prefix}.summary_report.md"
evidence_index = final_dir / f"{prefix}.summary_evidence_index.md"
files_tsv = final_dir / f"{prefix}.summary.files.tsv"
manifest_out = final_dir / f"{prefix}.summary.manifest.json"
write_files_tsv(files_tsv, artifact_rows)
write_report(report, prefix, summaries, checks, files_tsv)
write_report(evidence_index, prefix, summaries, checks, files_tsv)
manifest_data = {
"manifest_version": "1.0",
@@ -306,22 +314,24 @@ def main():
"summaries": summaries,
"checks": checks,
"artifacts": {
"summary_report": {"path": f"final/{report.name}", "type": "markdown", "size": report.stat().st_size},
"summary_evidence_index": {"path": f"final/{evidence_index.name}", "type": "markdown", "size": evidence_index.stat().st_size},
"files_tsv": {"path": f"final/{files_tsv.name}", "type": "tsv", "size": files_tsv.stat().st_size},
},
}
manifest_out.write_text(json.dumps(manifest_data, indent=2, ensure_ascii=False), encoding="utf-8")
scoped_manifest = None
scoped_data = None
if scope_id:
scoped_items = [x for x in summaries if x["scope_id"] == scope_id]
scoped_rows = [row for x in scoped_items for row in x["artifact_rows"]]
scoped_checks = [x for x in checks if x["scope_id"] in {scope_id, "all"}]
token = sanitize_token(scope_id)
scoped_report = final_dir / f"{prefix}.{token}.summary_report.md"
scoped_evidence_index = final_dir / f"{prefix}.{token}.summary_evidence_index.md"
scoped_files = final_dir / f"{prefix}.{token}.summary.files.tsv"
scoped_manifest = final_dir / f"{prefix}.{token}.summary.manifest.json"
write_files_tsv(scoped_files, scoped_rows)
write_report(scoped_report, prefix, scoped_items, scoped_checks, scoped_files)
write_report(scoped_evidence_index, prefix, scoped_items, scoped_checks, scoped_files)
scoped_data = dict(manifest_data)
scoped_data.update({
"scope_id": scope_id,
@@ -334,14 +344,79 @@ def main():
"summaries": scoped_items,
"checks": scoped_checks,
"artifacts": {
"summary_report": {"path": f"final/{scoped_report.name}", "type": "markdown", "size": scoped_report.stat().st_size},
"summary_evidence_index": {"path": f"final/{scoped_evidence_index.name}", "type": "markdown", "size": scoped_evidence_index.stat().st_size},
"files_tsv": {"path": f"final/{scoped_files.name}", "type": "tsv", "size": scoped_files.stat().st_size},
},
})
scoped_manifest.write_text(json.dumps(scoped_data, indent=2, ensure_ascii=False), encoding="utf-8")
if args.no_deepseek:
fallback_report = final_dir / (
f"{prefix}.{sanitize_token(scope_id)}.summary_report.md" if scope_id else f"{prefix}.summary_report.md"
)
source_index = scoped_evidence_index if scope_id else evidence_index
fallback_report.write_text(source_index.read_text(encoding="utf-8"), encoding="utf-8")
target_manifest = scoped_manifest if scope_id and scoped_manifest else manifest_out
target_data = read_json(target_manifest) or manifest_data
target_data.setdefault("artifacts", {})["summary_report"] = {
"path": f"final/{fallback_report.name}",
"type": "markdown",
"size": fallback_report.stat().st_size,
"generation": "deterministic_no_deepseek",
}
target_data["deepseek_generation"] = {"status": "skipped", "reason": "--no-deepseek"}
target_manifest.write_text(json.dumps(target_data, indent=2, ensure_ascii=False), encoding="utf-8")
else:
try:
from gfa_core.mas.agents.deepseek_summary import generate_deepseek_summary
result = generate_deepseek_summary(
final_dir=final_dir,
prefix=prefix,
job_id=workspace.name,
summaries=summaries,
scope_id=scope_id,
framework_path=Path(args.framework).expanduser() if args.framework else None,
model=args.deepseek_model,
max_tokens=max(4096, int(args.deepseek_max_tokens)),
)
effective_scope = str(result.get("scope_id") or "")
target_manifest = scoped_manifest if scope_id and scoped_manifest else manifest_out
target_data = read_json(target_manifest) or manifest_data
report_path = Path(result["report_path"])
evidence_path = Path(result["evidence_path"])
metadata_path = Path(result["metadata_path"])
target_data.setdefault("artifacts", {}).update({
"summary_report": {
"path": f"final/{report_path.name}", "type": "markdown", "size": report_path.stat().st_size,
"generation": "deepseek_api",
},
"summary_evidence": {
"path": f"final/{evidence_path.name}", "type": "json", "size": evidence_path.stat().st_size,
},
"deepseek_metadata": {
"path": f"final/{metadata_path.name}", "type": "json", "size": metadata_path.stat().st_size,
},
})
target_data["deepseek_generation"] = {
"status": "success",
"scope_id": effective_scope,
"provider": result["metadata"].get("provider"),
"model": result["metadata"].get("model"),
"validation": result["metadata"].get("validation"),
}
target_manifest.write_text(json.dumps(target_data, indent=2, ensure_ascii=False), encoding="utf-8")
except Exception as exc:
target_manifest = scoped_manifest if scope_id and scoped_manifest else manifest_out
target_data = read_json(target_manifest) or manifest_data
target_data["status"] = "failed"
target_data["deepseek_generation"] = {"status": "failed", "error": str(exc)[:2000]}
target_manifest.write_text(json.dumps(target_data, indent=2, ensure_ascii=False), encoding="utf-8")
print(f"Error: DeepSeek summary generation failed: {exc}", file=sys.stderr)
sys.exit(2)
print("Summary complete")
print(f" - {report}")
print(f" - {evidence_index}")
print(f" - {files_tsv}")
print(f" - {manifest_out}")