feat(governance): 新增 AI 技術雷達滾動監控
Some checks failed
Code Review / ai-code-review (push) Successful in 13s
CD Pipeline / tests (push) Successful in 1m39s
CD Pipeline / build-and-deploy (push) Successful in 4m35s
CD Pipeline / post-deploy-checks (push) Successful in 1m51s
Ansible / Reboot Recovery Contract / validate (push) Has been cancelled
Some checks failed
Code Review / ai-code-review (push) Successful in 13s
CD Pipeline / tests (push) Successful in 1m39s
CD Pipeline / build-and-deploy (push) Successful in 4m35s
CD Pipeline / post-deploy-checks (push) Successful in 1m51s
Ansible / Reboot Recovery Contract / validate (push) Has been cancelled
This commit is contained in:
110
.gitea/workflows/ai-technology-watch.yaml
Normal file
110
.gitea/workflows/ai-technology-watch.yaml
Normal file
@@ -0,0 +1,110 @@
|
|||||||
|
# =============================================================================
|
||||||
|
# AWOOOI AI Technology Watch (Gitea Actions)
|
||||||
|
# =============================================================================
|
||||||
|
# 每 6 小時只讀監控主流 AI 技術 primary sources。此 workflow 只產生
|
||||||
|
# Gitea step summary;不安裝 SDK、不呼叫 LLM API、不 commit report、不發
|
||||||
|
# Telegram、不切換 provider route、不修改 production。
|
||||||
|
|
||||||
|
name: AI 技術雷達監控
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
schedule:
|
||||||
|
- cron: '0 */6 * * *'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
ai-technology-watch:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
timeout-minutes: 10
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: 執行只讀 AI 技術雷達監控
|
||||||
|
id: watch
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
REPORT="/tmp/ai_technology_watch_report.json"
|
||||||
|
PREVIOUS_REPORT="$(find docs/evaluations -maxdepth 1 -type f -name 'ai_technology_watch_report_*.json' | sort | tail -n 1 || true)"
|
||||||
|
PREVIOUS_ARGS=()
|
||||||
|
if [ -n "$PREVIOUS_REPORT" ]; then
|
||||||
|
PREVIOUS_ARGS=(--previous-report "$PREVIOUS_REPORT")
|
||||||
|
echo "使用已提交的上一份 AI 技術雷達 baseline: $PREVIOUS_REPORT"
|
||||||
|
else
|
||||||
|
echo "找不到已提交的 AI 技術雷達 baseline,執行第一次 live baseline。"
|
||||||
|
fi
|
||||||
|
|
||||||
|
python3 scripts/agents/ai-technology-watch.py \
|
||||||
|
--registry docs/ai/ai-technology-watch-sources.v1.json \
|
||||||
|
--output "$REPORT" \
|
||||||
|
--mode live \
|
||||||
|
--timeout-seconds 12 \
|
||||||
|
"${PREVIOUS_ARGS[@]}"
|
||||||
|
|
||||||
|
python3 -m json.tool "$REPORT" >/dev/null
|
||||||
|
python3 - "$REPORT" <<'PY'
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
|
||||||
|
report_path = sys.argv[1]
|
||||||
|
with open(report_path, encoding="utf-8") as handle:
|
||||||
|
data = json.load(handle)
|
||||||
|
|
||||||
|
if data.get("schema_version") != "ai_technology_watch_report_v1":
|
||||||
|
raise SystemExit("AI 技術雷達 schema_version 不正確")
|
||||||
|
if data.get("mode") != "live":
|
||||||
|
raise SystemExit("AI 技術雷達 workflow 必須以 live mode 執行")
|
||||||
|
|
||||||
|
policy = data.get("policy") or {}
|
||||||
|
forbidden = [
|
||||||
|
"sdk_installation_approved",
|
||||||
|
"paid_api_calls_approved",
|
||||||
|
"production_routing_approved",
|
||||||
|
"telegram_send_approved",
|
||||||
|
"model_provider_switch_approved",
|
||||||
|
"host_write_approved",
|
||||||
|
]
|
||||||
|
unsafe = [key for key in forbidden if policy.get(key) is not False]
|
||||||
|
if unsafe:
|
||||||
|
raise SystemExit(f"AI 技術雷達 policy 必須維持 false: {unsafe}")
|
||||||
|
if policy.get("read_only") is not True:
|
||||||
|
raise SystemExit("AI 技術雷達必須維持 read_only")
|
||||||
|
|
||||||
|
summary = data.get("summary")
|
||||||
|
if not isinstance(summary, dict):
|
||||||
|
raise SystemExit("缺少 AI 技術雷達 summary")
|
||||||
|
required = [
|
||||||
|
"technology_count",
|
||||||
|
"technology_area_count",
|
||||||
|
"source_count",
|
||||||
|
"changed_technologies",
|
||||||
|
"watch_only_technologies",
|
||||||
|
"review_queue_count",
|
||||||
|
"source_failure_count",
|
||||||
|
"high_priority_count",
|
||||||
|
]
|
||||||
|
missing = [key for key in required if key not in summary]
|
||||||
|
if missing:
|
||||||
|
raise SystemExit(f"缺少 AI 技術雷達 summary keys: {missing}")
|
||||||
|
|
||||||
|
output_path = os.environ.get("GITHUB_OUTPUT")
|
||||||
|
if output_path:
|
||||||
|
with open(output_path, "a", encoding="utf-8") as handle:
|
||||||
|
for key in required:
|
||||||
|
handle.write(f"{key}={summary.get(key, 0)}\n")
|
||||||
|
|
||||||
|
step_summary_path = os.environ.get("GITHUB_STEP_SUMMARY")
|
||||||
|
if step_summary_path:
|
||||||
|
with open(step_summary_path, "a", encoding="utf-8") as handle:
|
||||||
|
handle.write("## AI 技術雷達監控\n\n")
|
||||||
|
handle.write(f"- 技術項目:{summary['technology_count']}\n")
|
||||||
|
handle.write(f"- 技術領域:{summary['technology_area_count']}\n")
|
||||||
|
handle.write(f"- 來源數:{summary['source_count']}\n")
|
||||||
|
handle.write(f"- 變更技術:{summary['changed_technologies']}\n")
|
||||||
|
handle.write(f"- 審核佇列:{summary['review_queue_count']}\n")
|
||||||
|
handle.write(f"- 來源失敗:{summary['source_failure_count']}\n")
|
||||||
|
handle.write(f"- 高優先級技術:{summary['high_priority_count']}\n")
|
||||||
|
handle.write("\nPolicy: 只讀監控;此 workflow 不批准 SDK/API/provider/Telegram/host/production 變更。\n")
|
||||||
|
|
||||||
|
print(json.dumps(summary, ensure_ascii=False, sort_keys=True))
|
||||||
|
PY
|
||||||
@@ -41,6 +41,9 @@ from src.services.agent_market_governance_snapshot import (
|
|||||||
from src.services.ai_agent_market_radar_readback import (
|
from src.services.ai_agent_market_radar_readback import (
|
||||||
load_latest_ai_agent_market_radar_readback,
|
load_latest_ai_agent_market_radar_readback,
|
||||||
)
|
)
|
||||||
|
from src.services.ai_technology_radar_readback import (
|
||||||
|
load_latest_ai_technology_radar_readback,
|
||||||
|
)
|
||||||
from src.services.agent_service import (
|
from src.services.agent_service import (
|
||||||
AgentService,
|
AgentService,
|
||||||
TaskState,
|
TaskState,
|
||||||
@@ -718,6 +721,35 @@ async def get_ai_agent_market_radar_readback() -> dict[str, Any]:
|
|||||||
) from exc
|
) from exc
|
||||||
|
|
||||||
|
|
||||||
|
@router.get(
|
||||||
|
"/ai-technology-radar-readback",
|
||||||
|
response_model=dict[str, Any],
|
||||||
|
summary="取得 AI 技術雷達與滾動更新讀回",
|
||||||
|
description=(
|
||||||
|
"讀取最新已提交的 AI 技術雷達 readback;"
|
||||||
|
"此端點只呈現 AI 技術 primary sources、技術領域、審核佇列、Agent 分工與滾動更新 Gate。"
|
||||||
|
"它不呼叫外部來源、不安裝 SDK、不呼叫付費 API、不切換模型、不送 Telegram、"
|
||||||
|
"不改主機、不修改 production routing、不替換 OpenClaw。"
|
||||||
|
),
|
||||||
|
)
|
||||||
|
async def get_ai_technology_radar_readback() -> dict[str, Any]:
|
||||||
|
"""回傳最新 AI 技術雷達與滾動更新只讀快照。"""
|
||||||
|
try:
|
||||||
|
payload = await asyncio.to_thread(load_latest_ai_technology_radar_readback)
|
||||||
|
return redact_public_lan_topology(payload)
|
||||||
|
except FileNotFoundError as exc:
|
||||||
|
raise HTTPException(
|
||||||
|
status_code=status.HTTP_404_NOT_FOUND,
|
||||||
|
detail=str(exc),
|
||||||
|
) from exc
|
||||||
|
except (json.JSONDecodeError, ValueError) as exc:
|
||||||
|
logger.error("ai_technology_radar_readback_invalid", error=str(exc))
|
||||||
|
raise HTTPException(
|
||||||
|
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||||||
|
detail="AI 技術雷達 readback 無效",
|
||||||
|
) from exc
|
||||||
|
|
||||||
|
|
||||||
@router.get(
|
@router.get(
|
||||||
"/automation-inventory-snapshot",
|
"/automation-inventory-snapshot",
|
||||||
response_model=dict[str, Any],
|
response_model=dict[str, Any],
|
||||||
|
|||||||
@@ -291,6 +291,16 @@ def _parse_source(source_type: str, body: bytes) -> dict[str, str | None]:
|
|||||||
"version": str(version) if version else None,
|
"version": str(version) if version else None,
|
||||||
"published_at": str(published_at) if published_at else None,
|
"published_at": str(published_at) if published_at else None,
|
||||||
}
|
}
|
||||||
|
if source_type == "github_tags":
|
||||||
|
payload = _loads_json(body)
|
||||||
|
if isinstance(payload, list) and payload:
|
||||||
|
first = payload[0]
|
||||||
|
if isinstance(first, dict):
|
||||||
|
version = first.get("name")
|
||||||
|
return {
|
||||||
|
"version": str(version) if version else None,
|
||||||
|
"published_at": None,
|
||||||
|
}
|
||||||
return {"version": None, "published_at": None}
|
return {"version": None, "published_at": None}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
68
apps/api/src/services/ai_technology_radar_readback.py
Normal file
68
apps/api/src/services/ai_technology_radar_readback.py
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
"""
|
||||||
|
AI technology radar readback.
|
||||||
|
|
||||||
|
Loads the committed read-only AI technology radar artifact. The radar is an
|
||||||
|
operator decision surface only; it does not approve SDK installs, paid API
|
||||||
|
calls, production routing, Telegram sends, host writes, or OpenClaw replacement.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import json
|
||||||
|
from pathlib import Path
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
|
from src.services.snapshot_paths import default_operations_dir
|
||||||
|
|
||||||
|
_DEFAULT_OPERATIONS_DIR = default_operations_dir(Path(__file__))
|
||||||
|
_SNAPSHOT_NAME = "ai-technology-radar-readback.snapshot.json"
|
||||||
|
|
||||||
|
|
||||||
|
def load_latest_ai_technology_radar_readback(
|
||||||
|
operations_dir: Path | None = None,
|
||||||
|
) -> dict[str, Any]:
|
||||||
|
"""Load the committed AI technology radar readback snapshot."""
|
||||||
|
directory = operations_dir or _DEFAULT_OPERATIONS_DIR
|
||||||
|
snapshot_path = directory / _SNAPSHOT_NAME
|
||||||
|
with snapshot_path.open(encoding="utf-8") as handle:
|
||||||
|
payload = json.load(handle)
|
||||||
|
|
||||||
|
if not isinstance(payload, dict):
|
||||||
|
raise ValueError(f"{snapshot_path}: expected JSON object")
|
||||||
|
if payload.get("schema_version") != "ai_technology_radar_readback_v1":
|
||||||
|
raise ValueError(f"{snapshot_path}: unexpected schema_version")
|
||||||
|
|
||||||
|
policy = payload.get("policy") or {}
|
||||||
|
forbidden_true = [
|
||||||
|
key
|
||||||
|
for key in [
|
||||||
|
"sdk_installation_approved",
|
||||||
|
"paid_api_calls_approved",
|
||||||
|
"production_routing_approved",
|
||||||
|
"telegram_send_approved",
|
||||||
|
"model_provider_switch_approved",
|
||||||
|
"host_write_approved",
|
||||||
|
"openclaw_replacement_approved",
|
||||||
|
]
|
||||||
|
if policy.get(key) is not False
|
||||||
|
]
|
||||||
|
if forbidden_true:
|
||||||
|
raise ValueError(f"{snapshot_path}: unsafe policy flags: {forbidden_true}")
|
||||||
|
if policy.get("read_only") is not True:
|
||||||
|
raise ValueError(f"{snapshot_path}: read_only policy must be true")
|
||||||
|
|
||||||
|
serialized = json.dumps(payload, ensure_ascii=False)
|
||||||
|
forbidden_fragments = [
|
||||||
|
"/Users/",
|
||||||
|
".claude/projects",
|
||||||
|
".codex",
|
||||||
|
"192.168.",
|
||||||
|
"auth.json",
|
||||||
|
"conversations",
|
||||||
|
"sessions",
|
||||||
|
]
|
||||||
|
leaked = [fragment for fragment in forbidden_fragments if fragment in serialized]
|
||||||
|
if leaked:
|
||||||
|
raise ValueError(f"{snapshot_path}: forbidden local or raw-history fragment: {leaked}")
|
||||||
|
|
||||||
|
return payload
|
||||||
183
apps/api/src/services/ai_technology_watch.py
Normal file
183
apps/api/src/services/ai_technology_watch.py
Normal file
@@ -0,0 +1,183 @@
|
|||||||
|
"""
|
||||||
|
AI technology watch service.
|
||||||
|
|
||||||
|
Builds a read-only cross-domain AI technology radar from primary sources. This
|
||||||
|
wraps the existing market-watch fetcher so the broader radar uses the same
|
||||||
|
no-SDK, no-paid-API, no-production-change boundary as the Agent market watch.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import importlib.util
|
||||||
|
import sys
|
||||||
|
from collections import Counter
|
||||||
|
from collections.abc import Callable
|
||||||
|
from datetime import datetime, timezone
|
||||||
|
from pathlib import Path
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
|
FetchSource = Callable[[str, int], Any]
|
||||||
|
|
||||||
|
_AGENT_MARKET_WATCH_MODULE = None
|
||||||
|
|
||||||
|
|
||||||
|
def run_ai_technology_watch(
|
||||||
|
registry: dict[str, Any],
|
||||||
|
*,
|
||||||
|
registry_path: str,
|
||||||
|
mode: str = "live",
|
||||||
|
previous_report: dict[str, Any] | None = None,
|
||||||
|
timeout_seconds: int = 12,
|
||||||
|
fetcher: FetchSource | None = None,
|
||||||
|
generated_at: str | None = None,
|
||||||
|
) -> dict[str, Any]:
|
||||||
|
"""Build a broad read-only AI technology watch report."""
|
||||||
|
run_agent_market_watch = _load_agent_market_watch_runner()
|
||||||
|
agent_previous = _to_agent_previous_report(previous_report or {})
|
||||||
|
raw_report = run_agent_market_watch(
|
||||||
|
registry,
|
||||||
|
registry_path=registry_path,
|
||||||
|
mode=mode,
|
||||||
|
previous_report=agent_previous,
|
||||||
|
timeout_seconds=timeout_seconds,
|
||||||
|
fetcher=fetcher,
|
||||||
|
generated_at=generated_at,
|
||||||
|
)
|
||||||
|
registry_by_id = {
|
||||||
|
str(item.get("candidate_id", "")).strip(): item
|
||||||
|
for item in registry.get("candidates") or []
|
||||||
|
if str(item.get("candidate_id", "")).strip()
|
||||||
|
}
|
||||||
|
technologies = [
|
||||||
|
_technology_row(raw_candidate, registry_by_id.get(raw_candidate["candidate_id"], {}))
|
||||||
|
for raw_candidate in raw_report.get("candidates") or []
|
||||||
|
]
|
||||||
|
area_counts = Counter(row["technology_area"] for row in technologies)
|
||||||
|
priority_counts = Counter(row["evaluation_priority"] for row in technologies)
|
||||||
|
changed = [row for row in technologies if row["changed"]]
|
||||||
|
|
||||||
|
return {
|
||||||
|
"schema_version": "ai_technology_watch_report_v1",
|
||||||
|
"generated_at": generated_at or datetime.now(timezone.utc).isoformat(),
|
||||||
|
"mode": mode,
|
||||||
|
"registry": {
|
||||||
|
"path": registry_path,
|
||||||
|
"schema_version": str(registry.get("schema_version", "")),
|
||||||
|
"updated_at": str(registry.get("updated_at", "")),
|
||||||
|
},
|
||||||
|
"cadence": dict(registry.get("cadence") or {}),
|
||||||
|
"policy": _policy(registry),
|
||||||
|
"summary": {
|
||||||
|
"technology_count": len(technologies),
|
||||||
|
"technology_area_count": len(area_counts),
|
||||||
|
"source_count": raw_report["summary"]["source_count"],
|
||||||
|
"changed_technologies": len(changed),
|
||||||
|
"watch_only_technologies": len(technologies) - len(changed),
|
||||||
|
"review_queue_count": len(changed),
|
||||||
|
"source_failure_count": raw_report["summary"]["failure_count"],
|
||||||
|
"high_priority_count": priority_counts.get("p0", 0)
|
||||||
|
+ priority_counts.get("p1", 0),
|
||||||
|
},
|
||||||
|
"technology_area_counts": dict(sorted(area_counts.items())),
|
||||||
|
"technologies": technologies,
|
||||||
|
"review_queue": [_review_queue_item(row) for row in changed],
|
||||||
|
"new_technology_discovery": raw_report.get("new_candidate_discovery") or [],
|
||||||
|
"failures": raw_report.get("failures") or [],
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def _load_agent_market_watch_runner() -> Any:
|
||||||
|
global _AGENT_MARKET_WATCH_MODULE
|
||||||
|
if _AGENT_MARKET_WATCH_MODULE is not None:
|
||||||
|
return _AGENT_MARKET_WATCH_MODULE.run_agent_market_watch
|
||||||
|
|
||||||
|
module_name = "awoooi_agent_market_watch_service_for_ai_technology"
|
||||||
|
service_path = Path(__file__).with_name("agent_market_watch.py")
|
||||||
|
spec = importlib.util.spec_from_file_location(module_name, service_path)
|
||||||
|
if spec is None or spec.loader is None:
|
||||||
|
raise RuntimeError(f"cannot load agent market watch service from {service_path}")
|
||||||
|
module = importlib.util.module_from_spec(spec)
|
||||||
|
sys.modules[module_name] = module
|
||||||
|
spec.loader.exec_module(module)
|
||||||
|
_AGENT_MARKET_WATCH_MODULE = module
|
||||||
|
return module.run_agent_market_watch
|
||||||
|
|
||||||
|
|
||||||
|
def _policy(registry: dict[str, Any]) -> dict[str, Any]:
|
||||||
|
policy = dict(registry.get("policy") or {})
|
||||||
|
policy.setdefault("read_only", True)
|
||||||
|
policy.setdefault("sdk_installation_approved", False)
|
||||||
|
policy.setdefault("paid_api_calls_approved", False)
|
||||||
|
policy.setdefault("production_routing_approved", False)
|
||||||
|
policy.setdefault("workflow_modification_approved", False)
|
||||||
|
policy.setdefault("telegram_send_approved", False)
|
||||||
|
policy.setdefault("model_provider_switch_approved", False)
|
||||||
|
policy.setdefault("host_write_approved", False)
|
||||||
|
return policy
|
||||||
|
|
||||||
|
|
||||||
|
def _technology_row(raw_candidate: dict[str, Any], registry_candidate: dict[str, Any]) -> dict[str, Any]:
|
||||||
|
return {
|
||||||
|
"technology_id": raw_candidate["candidate_id"],
|
||||||
|
"display_name": raw_candidate["display_name"],
|
||||||
|
"technology_area": str(registry_candidate.get("technology_area") or "uncategorized"),
|
||||||
|
"integration_surface": str(registry_candidate.get("integration_surface") or "watch_only"),
|
||||||
|
"awoooi_role": str(registry_candidate.get("awoooi_role") or raw_candidate.get("recommended_role") or ""),
|
||||||
|
"evaluation_priority": raw_candidate.get("evaluation_priority") or "watch",
|
||||||
|
"requires_cost_approval": bool(raw_candidate.get("requires_cost_approval")),
|
||||||
|
"requires_dependency_approval": bool(raw_candidate.get("requires_dependency_approval")),
|
||||||
|
"requires_security_review": bool(registry_candidate.get("requires_security_review", True)),
|
||||||
|
"sources": raw_candidate.get("sources") or [],
|
||||||
|
"changed": bool(raw_candidate.get("changed")),
|
||||||
|
"decision": raw_candidate.get("decision"),
|
||||||
|
"recommended_actions": _recommended_actions(raw_candidate, registry_candidate),
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def _recommended_actions(
|
||||||
|
raw_candidate: dict[str, Any],
|
||||||
|
registry_candidate: dict[str, Any],
|
||||||
|
) -> list[str]:
|
||||||
|
if raw_candidate.get("changed"):
|
||||||
|
return [
|
||||||
|
"refresh_ai_technology_scorecard",
|
||||||
|
"classify_business_applicability",
|
||||||
|
"prepare_no_install_integration_note",
|
||||||
|
"route_high_risk_items_to_human_review",
|
||||||
|
]
|
||||||
|
if any(source.get("error") for source in raw_candidate.get("sources") or []):
|
||||||
|
return ["retry_primary_source_fetch", "keep_current_runtime_status"]
|
||||||
|
actions = list(registry_candidate.get("steady_state_actions") or [])
|
||||||
|
return actions or ["keep_watch_only_status"]
|
||||||
|
|
||||||
|
|
||||||
|
def _review_queue_item(row: dict[str, Any]) -> dict[str, Any]:
|
||||||
|
return {
|
||||||
|
"technology_id": row["technology_id"],
|
||||||
|
"technology_area": row["technology_area"],
|
||||||
|
"reason": "primary_source_version_or_content_changed",
|
||||||
|
"required_next_gate": "scorecard_then_sandbox_or_replay_plan",
|
||||||
|
"requires_cost_approval": row["requires_cost_approval"],
|
||||||
|
"requires_dependency_approval": row["requires_dependency_approval"],
|
||||||
|
"requires_security_review": row["requires_security_review"],
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def _to_agent_previous_report(report: dict[str, Any]) -> dict[str, Any] | None:
|
||||||
|
if not report:
|
||||||
|
return None
|
||||||
|
if report.get("schema_version") == "agent_market_watch_report_v1":
|
||||||
|
return report
|
||||||
|
if report.get("schema_version") != "ai_technology_watch_report_v1":
|
||||||
|
return None
|
||||||
|
return {
|
||||||
|
"schema_version": "agent_market_watch_report_v1",
|
||||||
|
"candidates": [
|
||||||
|
{
|
||||||
|
"candidate_id": row.get("technology_id"),
|
||||||
|
"sources": row.get("sources") or [],
|
||||||
|
}
|
||||||
|
for row in report.get("technologies") or []
|
||||||
|
if row.get("technology_id")
|
||||||
|
],
|
||||||
|
}
|
||||||
@@ -225,6 +225,48 @@ def test_docs_hash_ignores_dynamic_script_noise():
|
|||||||
assert second_report["candidates"][0]["sources"][0]["changed_since_reference"] is False
|
assert second_report["candidates"][0]["sources"][0]["changed_since_reference"] is False
|
||||||
|
|
||||||
|
|
||||||
|
def test_market_watch_parses_github_tags_for_projects_without_releases():
|
||||||
|
registry = {
|
||||||
|
"schema_version": "agent_market_watch_sources_v1",
|
||||||
|
"policy": {"replacement_decision_allowed": False},
|
||||||
|
"candidates": [
|
||||||
|
{
|
||||||
|
"candidate_id": "pgvector",
|
||||||
|
"display_name": "pgvector",
|
||||||
|
"evaluation_priority": "watch",
|
||||||
|
"recommended_role": "vector store",
|
||||||
|
"sources": [
|
||||||
|
{
|
||||||
|
"source_id": "pgvector_tags",
|
||||||
|
"type": "github_tags",
|
||||||
|
"url": "https://api.github.com/repos/pgvector/pgvector/tags",
|
||||||
|
}
|
||||||
|
],
|
||||||
|
}
|
||||||
|
],
|
||||||
|
}
|
||||||
|
|
||||||
|
def fetcher(_url: str, _timeout: int) -> FetchedSource:
|
||||||
|
return FetchedSource(
|
||||||
|
status="ok",
|
||||||
|
http_status=200,
|
||||||
|
body=json.dumps([{"name": "v0.8.0"}]).encode(),
|
||||||
|
)
|
||||||
|
|
||||||
|
report = run_agent_market_watch(
|
||||||
|
registry,
|
||||||
|
registry_path="registry.json",
|
||||||
|
mode="live",
|
||||||
|
fetcher=fetcher,
|
||||||
|
generated_at="2026-06-25T00:00:00+00:00",
|
||||||
|
)
|
||||||
|
|
||||||
|
source = report["candidates"][0]["sources"][0]
|
||||||
|
assert source["status"] == "ok"
|
||||||
|
assert source["version"] == "v0.8.0"
|
||||||
|
assert report["summary"]["failure_count"] == 0
|
||||||
|
|
||||||
|
|
||||||
def test_versioned_source_ignores_metadata_hash_noise_when_version_is_unchanged():
|
def test_versioned_source_ignores_metadata_hash_noise_when_version_is_unchanged():
|
||||||
registry = {
|
registry = {
|
||||||
"schema_version": "agent_market_watch_sources_v1",
|
"schema_version": "agent_market_watch_sources_v1",
|
||||||
|
|||||||
61
apps/api/tests/test_ai_technology_radar_readback.py
Normal file
61
apps/api/tests/test_ai_technology_radar_readback.py
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import json
|
||||||
|
|
||||||
|
from src.services.ai_technology_radar_readback import (
|
||||||
|
load_latest_ai_technology_radar_readback,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def test_ai_technology_radar_readback_committed_snapshot_is_safe():
|
||||||
|
payload = load_latest_ai_technology_radar_readback()
|
||||||
|
|
||||||
|
assert payload["schema_version"] == "ai_technology_radar_readback_v1"
|
||||||
|
assert payload["summary"]["overall_completion_percent"] == 42.2
|
||||||
|
assert payload["summary"]["ai_technology_radar_completion_percent"] == 100.0
|
||||||
|
assert payload["summary"]["technology_count"] == 20
|
||||||
|
assert payload["summary"]["technology_area_count"] == 6
|
||||||
|
assert payload["summary"]["source_count"] == 47
|
||||||
|
assert payload["summary"]["source_failures"] == 0
|
||||||
|
assert payload["summary"]["high_priority_count"] == 14
|
||||||
|
assert payload["summary"]["rolling_update_status"] == (
|
||||||
|
"near_real_time_watch_ready_integration_gated"
|
||||||
|
)
|
||||||
|
assert payload["source_scope"]["gitea_main_evidence_basis_commit"] == "683428bd"
|
||||||
|
|
||||||
|
policy = payload["policy"]
|
||||||
|
assert policy["read_only"] is True
|
||||||
|
assert policy["raw_chat_history_synced"] is False
|
||||||
|
assert policy["sdk_installation_approved"] is False
|
||||||
|
assert policy["paid_api_calls_approved"] is False
|
||||||
|
assert policy["production_routing_approved"] is False
|
||||||
|
assert policy["telegram_send_approved"] is False
|
||||||
|
assert policy["model_provider_switch_approved"] is False
|
||||||
|
assert policy["host_write_approved"] is False
|
||||||
|
assert policy["openclaw_replacement_approved"] is False
|
||||||
|
|
||||||
|
serialized = json.dumps(payload, ensure_ascii=False)
|
||||||
|
assert "/Users/" not in serialized
|
||||||
|
assert ".claude/projects" not in serialized
|
||||||
|
assert ".codex" not in serialized
|
||||||
|
assert "192.168." not in serialized
|
||||||
|
assert "auth.json" not in serialized
|
||||||
|
|
||||||
|
|
||||||
|
def test_ai_technology_radar_readback_contains_roles_and_cadence():
|
||||||
|
payload = load_latest_ai_technology_radar_readback()
|
||||||
|
|
||||||
|
roles = {row["agent"]: row for row in payload["professional_agent_roles"]}
|
||||||
|
assert "OpenClaw" in roles
|
||||||
|
assert "NemoTron" in roles
|
||||||
|
assert "Hermes" in roles
|
||||||
|
assert "MarketRadar" in roles
|
||||||
|
assert "生產路由" in roles["OpenClaw"]["review_boundary"]
|
||||||
|
assert "離線回放評估者" in roles["NemoTron"]["professional_role"]
|
||||||
|
|
||||||
|
controls = {row["cadence"]: row for row in payload["rolling_update_controls"]}
|
||||||
|
assert "每 6 小時" in controls
|
||||||
|
assert controls["每 6 小時"]["gate"] == "read_only_only"
|
||||||
|
assert payload["report_contract"]["api_endpoint"] == (
|
||||||
|
"/api/v1/agents/ai-technology-radar-readback"
|
||||||
|
)
|
||||||
35
apps/api/tests/test_ai_technology_radar_readback_api.py
Normal file
35
apps/api/tests/test_ai_technology_radar_readback_api.py
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import json
|
||||||
|
|
||||||
|
from fastapi import FastAPI
|
||||||
|
from fastapi.testclient import TestClient
|
||||||
|
|
||||||
|
from src.api.v1.agents import router
|
||||||
|
|
||||||
|
|
||||||
|
def test_ai_technology_radar_readback_endpoint_returns_committed_snapshot():
|
||||||
|
app = FastAPI()
|
||||||
|
app.include_router(router, prefix="/api/v1")
|
||||||
|
client = TestClient(app)
|
||||||
|
|
||||||
|
response = client.get("/api/v1/agents/ai-technology-radar-readback")
|
||||||
|
|
||||||
|
assert response.status_code == 200
|
||||||
|
data = response.json()
|
||||||
|
assert data["schema_version"] == "ai_technology_radar_readback_v1"
|
||||||
|
assert data["summary"]["overall_completion_percent"] == 42.2
|
||||||
|
assert data["summary"]["ai_technology_radar_completion_percent"] == 100.0
|
||||||
|
assert data["summary"]["technology_count"] == 20
|
||||||
|
assert data["summary"]["source_count"] == 47
|
||||||
|
assert data["summary"]["source_failures"] == 0
|
||||||
|
assert data["policy"]["read_only"] is True
|
||||||
|
assert data["policy"]["sdk_installation_approved"] is False
|
||||||
|
assert data["policy"]["telegram_send_approved"] is False
|
||||||
|
assert data["policy"]["openclaw_replacement_approved"] is False
|
||||||
|
|
||||||
|
serialized = json.dumps(data, ensure_ascii=False)
|
||||||
|
assert "/Users/" not in serialized
|
||||||
|
assert ".claude/projects" not in serialized
|
||||||
|
assert ".codex" not in serialized
|
||||||
|
assert "192.168." not in serialized
|
||||||
148
apps/api/tests/test_ai_technology_watch.py
Normal file
148
apps/api/tests/test_ai_technology_watch.py
Normal file
@@ -0,0 +1,148 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import json
|
||||||
|
|
||||||
|
from src.services.agent_market_watch import FetchedSource
|
||||||
|
from src.services.ai_technology_watch import run_ai_technology_watch
|
||||||
|
|
||||||
|
|
||||||
|
def test_ai_technology_watch_groups_areas_and_blocks_integration():
|
||||||
|
registry = {
|
||||||
|
"schema_version": "ai_technology_watch_sources_v1",
|
||||||
|
"updated_at": "2026-06-25",
|
||||||
|
"cadence": {
|
||||||
|
"near_real_time_watch": "每 6 小時",
|
||||||
|
"daily_triage": "每日",
|
||||||
|
"weekly_scorecard": "每週",
|
||||||
|
"monthly_strategy_review": "每月",
|
||||||
|
},
|
||||||
|
"policy": {
|
||||||
|
"read_only": True,
|
||||||
|
"sdk_installation_approved": False,
|
||||||
|
"paid_api_calls_approved": False,
|
||||||
|
"production_routing_approved": False,
|
||||||
|
"telegram_send_approved": False,
|
||||||
|
"model_provider_switch_approved": False,
|
||||||
|
"host_write_approved": False,
|
||||||
|
},
|
||||||
|
"candidates": [
|
||||||
|
{
|
||||||
|
"candidate_id": "langgraph_runtime",
|
||||||
|
"display_name": "LangGraph",
|
||||||
|
"technology_area": "agent_frameworks",
|
||||||
|
"integration_surface": "durable_workflow_human_in_loop",
|
||||||
|
"awoooi_role": "事件工作流候選",
|
||||||
|
"evaluation_priority": "p0",
|
||||||
|
"requires_cost_approval": False,
|
||||||
|
"requires_dependency_approval": True,
|
||||||
|
"requires_security_review": True,
|
||||||
|
"sources": [
|
||||||
|
{
|
||||||
|
"source_id": "langgraph_pypi",
|
||||||
|
"type": "pypi",
|
||||||
|
"url": "https://pypi.org/pypi/langgraph/json",
|
||||||
|
"reference_version": "1.0.0",
|
||||||
|
}
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"candidate_id": "ragas_eval",
|
||||||
|
"display_name": "Ragas",
|
||||||
|
"technology_area": "evaluation_and_observability",
|
||||||
|
"integration_surface": "rag_evaluation",
|
||||||
|
"awoooi_role": "RAG 品質評測候選",
|
||||||
|
"evaluation_priority": "p1",
|
||||||
|
"requires_cost_approval": False,
|
||||||
|
"requires_dependency_approval": True,
|
||||||
|
"requires_security_review": True,
|
||||||
|
"sources": [
|
||||||
|
{
|
||||||
|
"source_id": "ragas_pypi",
|
||||||
|
"type": "pypi",
|
||||||
|
"url": "https://pypi.org/pypi/ragas/json",
|
||||||
|
"reference_version": "0.1.0",
|
||||||
|
}
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
|
||||||
|
def fetcher(url: str, _timeout: int) -> FetchedSource:
|
||||||
|
version = "1.1.0" if "langgraph" in url else "0.1.0"
|
||||||
|
payload = {
|
||||||
|
"info": {"version": version},
|
||||||
|
"releases": {
|
||||||
|
version: [{"upload_time_iso_8601": "2026-06-25T01:02:03Z"}]
|
||||||
|
},
|
||||||
|
}
|
||||||
|
return FetchedSource(status="ok", http_status=200, body=json.dumps(payload).encode())
|
||||||
|
|
||||||
|
report = run_ai_technology_watch(
|
||||||
|
registry,
|
||||||
|
registry_path="docs/ai/ai-technology-watch-sources.v1.json",
|
||||||
|
mode="live",
|
||||||
|
fetcher=fetcher,
|
||||||
|
generated_at="2026-06-25T00:00:00+00:00",
|
||||||
|
)
|
||||||
|
|
||||||
|
assert report["schema_version"] == "ai_technology_watch_report_v1"
|
||||||
|
assert report["summary"]["technology_count"] == 2
|
||||||
|
assert report["summary"]["technology_area_count"] == 2
|
||||||
|
assert report["summary"]["changed_technologies"] == 1
|
||||||
|
assert report["summary"]["review_queue_count"] == 1
|
||||||
|
assert report["summary"]["high_priority_count"] == 2
|
||||||
|
assert report["technology_area_counts"]["agent_frameworks"] == 1
|
||||||
|
assert report["technology_area_counts"]["evaluation_and_observability"] == 1
|
||||||
|
assert report["policy"]["read_only"] is True
|
||||||
|
assert report["policy"]["sdk_installation_approved"] is False
|
||||||
|
assert report["policy"]["paid_api_calls_approved"] is False
|
||||||
|
assert report["policy"]["production_routing_approved"] is False
|
||||||
|
assert report["policy"]["telegram_send_approved"] is False
|
||||||
|
assert report["review_queue"][0]["technology_id"] == "langgraph_runtime"
|
||||||
|
|
||||||
|
|
||||||
|
def test_ai_technology_watch_reuses_previous_report_for_change_detection():
|
||||||
|
registry = {
|
||||||
|
"schema_version": "ai_technology_watch_sources_v1",
|
||||||
|
"updated_at": "2026-06-25",
|
||||||
|
"policy": {"read_only": True},
|
||||||
|
"candidates": [
|
||||||
|
{
|
||||||
|
"candidate_id": "mcp_sdk",
|
||||||
|
"display_name": "MCP SDK",
|
||||||
|
"technology_area": "mcp_and_a2a",
|
||||||
|
"evaluation_priority": "p0",
|
||||||
|
"sources": [
|
||||||
|
{
|
||||||
|
"source_id": "mcp_npm",
|
||||||
|
"type": "npm",
|
||||||
|
"url": "https://registry.npmjs.org/%40modelcontextprotocol%2Fsdk",
|
||||||
|
}
|
||||||
|
],
|
||||||
|
}
|
||||||
|
],
|
||||||
|
}
|
||||||
|
|
||||||
|
def fetcher(_url: str, _timeout: int) -> FetchedSource:
|
||||||
|
payload = {"dist-tags": {"latest": "1.2.3"}, "time": {"1.2.3": "2026-06-25"}}
|
||||||
|
return FetchedSource(status="ok", http_status=200, body=json.dumps(payload).encode())
|
||||||
|
|
||||||
|
first_report = run_ai_technology_watch(
|
||||||
|
registry,
|
||||||
|
registry_path="registry.json",
|
||||||
|
mode="live",
|
||||||
|
fetcher=fetcher,
|
||||||
|
generated_at="2026-06-25T00:00:00+00:00",
|
||||||
|
)
|
||||||
|
second_report = run_ai_technology_watch(
|
||||||
|
registry,
|
||||||
|
registry_path="registry.json",
|
||||||
|
mode="live",
|
||||||
|
previous_report=first_report,
|
||||||
|
fetcher=fetcher,
|
||||||
|
generated_at="2026-06-25T01:00:00+00:00",
|
||||||
|
)
|
||||||
|
|
||||||
|
assert first_report["summary"]["changed_technologies"] == 0
|
||||||
|
assert second_report["summary"]["changed_technologies"] == 0
|
||||||
|
assert second_report["technologies"][0]["sources"][0]["version"] == "1.2.3"
|
||||||
@@ -1,3 +1,32 @@
|
|||||||
|
## 2026-06-25|AI 技術雷達近即時監控與產品讀回
|
||||||
|
|
||||||
|
**背景**:使用者要求 AWOOOI 不能只評估 AI Agent,整個產品與網站必須持續、即時監控市場上所有主流 AI 技術,包含新技術、新版本、新整合與新應用,並能滾動更新到專案評估流程中。
|
||||||
|
|
||||||
|
**完成**:
|
||||||
|
- 新增 `docs/ai/ai-technology-watch-sources.v1.json`,監控範圍擴到 `agent_frameworks`、`model_providers`、`rag_and_vector`、`mcp_and_a2a`、`evaluation_and_observability`、`model_serving` 六大領域。
|
||||||
|
- 新增 `apps/api/src/services/ai_technology_watch.py` 與 `scripts/agents/ai-technology-watch.py`,沿用 AI Agent market watch 的只讀 primary-source fetch / change detection / review queue 邏輯。
|
||||||
|
- `agent_market_watch.py` 新增 `github_tags` source type,支援 pgvector 這類沒有 GitHub Release 但有 tags 的主流專案,避免誤報來源失敗。
|
||||||
|
- 新增 `docs/evaluations/ai_technology_watch_report_2026-06-25.json`:本輪 live 讀取 `20` 個技術項、`47` 個 primary sources、`6` 個技術領域,`source_failure_count=0`、`changed_technologies=0`、高優先級項目 `14`。
|
||||||
|
- 新增 `scripts/dev/ai-technology-radar-readback.py`、`docs/operations/ai-technology-radar-readback.snapshot.json`、`docs/operations/AI-TECHNOLOGY-RADAR-READBACK-2026-06-25.md` 與 `docs/operations/AI-TECHNOLOGY-RADAR-READBACK.md`。
|
||||||
|
- 新增 read-only API:`GET /api/v1/agents/ai-technology-radar-readback`,前端可讀 AI 技術雷達、Agent 專業分工、滾動更新節奏、審核佇列與 blocked gates。
|
||||||
|
- 新增 `.gitea/workflows/ai-technology-watch.yaml`,每 6 小時執行只讀 AI 技術監控並寫入 Gitea step summary;workflow 不 commit、不發 Telegram、不安裝 SDK、不呼叫 LLM API、不切 provider route、不改 production。
|
||||||
|
- 新增 schema 與測試:`ai_technology_watch_report_v1`、`ai_technology_radar_readback_v1`、watch service tests、readback loader tests、FastAPI endpoint tests。
|
||||||
|
|
||||||
|
**目前真相**:
|
||||||
|
- AI 技術雷達來源成功率:`100%`。
|
||||||
|
- AI 技術監控項目:`20`。
|
||||||
|
- primary sources:`47`。
|
||||||
|
- 技術領域:`6`。
|
||||||
|
- 需要審核變更:`0`。
|
||||||
|
- 來源失敗:`0`。
|
||||||
|
- OpenClaw 替換批准:`false`。
|
||||||
|
- SDK 安裝、付費 API、production routing、Telegram send、model provider switch、host write:全部仍為 `false`。
|
||||||
|
- OpenClaw / Hermes / NemoTron / MarketRadar / Critic-Reviewer 的專業分工已在 readback 中可讀;NemoTron 仍定位為 replay evaluator / smoke gate,不得直接進 production routing。
|
||||||
|
|
||||||
|
**邊界**:
|
||||||
|
- 本輪沒有安裝新 SDK、沒有呼叫付費 AI API、沒有發 Telegram、沒有修改 AI provider route、沒有主機寫入、沒有 Nginx / K8s / secret / runtime config 變更、沒有替換 OpenClaw。
|
||||||
|
- `.gitea/workflows/ai-technology-watch.yaml` 只啟用 read-only source monitoring;任何後續自動整合、套件升級、模型切換、Telegram live delivery 或 production change 仍需獨立 owner gate。
|
||||||
|
|
||||||
## 2026-06-25|Wazuh release / route readback 狀態收斂與 agent registry 未完成邊界
|
## 2026-06-25|Wazuh release / route readback 狀態收斂與 agent registry 未完成邊界
|
||||||
|
|
||||||
**背景**:Wazuh 用戶端消失事故的關鍵狀態已從「IwoooS production route 仍 404」前進到「route 已部署但 Wazuh live metadata / agent registry 尚未驗收」。本輪同步前台、release gate、live metadata env gate、handoff 與 LOGBOOK,避免 operator 或平行工作視窗把 route 200、agent transport、service active 或 UI 可見誤判成所有主機已納回 Wazuh。
|
**背景**:Wazuh 用戶端消失事故的關鍵狀態已從「IwoooS production route 仍 404」前進到「route 已部署但 Wazuh live metadata / agent registry 尚未驗收」。本輪同步前台、release gate、live metadata env gate、handoff 與 LOGBOOK,避免 operator 或平行工作視窗把 route 200、agent transport、service active 或 UI 可見誤判成所有主機已納回 Wazuh。
|
||||||
|
|||||||
563
docs/ai/ai-technology-watch-sources.v1.json
Normal file
563
docs/ai/ai-technology-watch-sources.v1.json
Normal file
@@ -0,0 +1,563 @@
|
|||||||
|
{
|
||||||
|
"schema_version": "ai_technology_watch_sources_v1",
|
||||||
|
"updated_at": "2026-06-25",
|
||||||
|
"cadence": {
|
||||||
|
"near_real_time_watch": "每 6 小時執行一次只讀 primary-source 檢查,偵測主流 AI 技術版本、文件與 release 變更。",
|
||||||
|
"daily_triage": "每日彙整變更技術,依商業適用性、依賴風險、成本風險與資安風險分組。",
|
||||||
|
"weekly_scorecard": "每週刷新技術 scorecard,判斷是否值得進入 sandbox、offline replay 或 adapter design。",
|
||||||
|
"monthly_strategy_review": "每月策略檢討,決定技術應納入 roadmap、維持 watch-only 或從監控清單移除。"
|
||||||
|
},
|
||||||
|
"policy": {
|
||||||
|
"read_only": true,
|
||||||
|
"raw_chat_history_synced": false,
|
||||||
|
"sdk_installation_approved": false,
|
||||||
|
"paid_api_calls_approved": false,
|
||||||
|
"production_routing_approved": false,
|
||||||
|
"workflow_modification_approved": false,
|
||||||
|
"telegram_send_approved": false,
|
||||||
|
"model_provider_switch_approved": false,
|
||||||
|
"host_write_approved": false
|
||||||
|
},
|
||||||
|
"coverage_contract": {
|
||||||
|
"scope": [
|
||||||
|
"agent_frameworks",
|
||||||
|
"model_providers",
|
||||||
|
"rag_and_vector",
|
||||||
|
"mcp_and_a2a",
|
||||||
|
"evaluation_and_observability",
|
||||||
|
"coding_agents",
|
||||||
|
"multimodal_generation"
|
||||||
|
],
|
||||||
|
"must_not_do": [
|
||||||
|
"安裝新 SDK",
|
||||||
|
"呼叫付費模型 API",
|
||||||
|
"修改 provider routing",
|
||||||
|
"修改 production prompts",
|
||||||
|
"發送 Telegram 指令",
|
||||||
|
"寫入主機",
|
||||||
|
"在缺少 replay / shadow / canary 證據時替換 OpenClaw"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"candidates": [
|
||||||
|
{
|
||||||
|
"candidate_id": "openai_agents_sdk",
|
||||||
|
"display_name": "OpenAI Agents SDK",
|
||||||
|
"technology_area": "agent_frameworks",
|
||||||
|
"integration_surface": "agent_handoff_tracing_guardrails",
|
||||||
|
"awoooi_role": "協調者、handoff、tool tracing、guardrail 候選",
|
||||||
|
"evaluation_priority": "p0",
|
||||||
|
"requires_cost_approval": true,
|
||||||
|
"requires_dependency_approval": true,
|
||||||
|
"requires_security_review": true,
|
||||||
|
"sources": [
|
||||||
|
{
|
||||||
|
"source_id": "openai_agents_python_pypi",
|
||||||
|
"type": "pypi",
|
||||||
|
"url": "https://pypi.org/pypi/openai-agents/json",
|
||||||
|
"reference_version": "0.17.7"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"source_id": "openai_agents_typescript_npm",
|
||||||
|
"type": "npm",
|
||||||
|
"url": "https://registry.npmjs.org/%40openai%2Fagents",
|
||||||
|
"reference_version": "0.12.0"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"source_id": "openai_agents_docs",
|
||||||
|
"type": "docs",
|
||||||
|
"url": "https://developers.openai.com/api/docs/guides/agents"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"candidate_id": "nvidia_nemotron_nemo",
|
||||||
|
"display_name": "NVIDIA Nemotron + NeMo Agent Toolkit",
|
||||||
|
"technology_area": "agent_frameworks",
|
||||||
|
"integration_surface": "offline_replay_evaluator_smoke_gate",
|
||||||
|
"awoooi_role": "NemoTron replay / evaluator / synthetic data gate",
|
||||||
|
"evaluation_priority": "p0",
|
||||||
|
"requires_cost_approval": true,
|
||||||
|
"requires_dependency_approval": true,
|
||||||
|
"requires_security_review": true,
|
||||||
|
"sources": [
|
||||||
|
{
|
||||||
|
"source_id": "nvidia_nemotron_developer_page",
|
||||||
|
"type": "docs",
|
||||||
|
"url": "https://developer.nvidia.com/topics/ai/nemotron"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"source_id": "nvidia_nemo_agent_toolkit_docs",
|
||||||
|
"type": "docs",
|
||||||
|
"url": "https://docs.nvidia.com/nemo/agent-toolkit/latest/index.html"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"candidate_id": "langgraph_runtime",
|
||||||
|
"display_name": "LangGraph",
|
||||||
|
"technology_area": "agent_frameworks",
|
||||||
|
"integration_surface": "durable_workflow_human_in_loop",
|
||||||
|
"awoooi_role": "事件處理與可恢復 workflow kernel 候選",
|
||||||
|
"evaluation_priority": "p0",
|
||||||
|
"requires_cost_approval": false,
|
||||||
|
"requires_dependency_approval": true,
|
||||||
|
"requires_security_review": true,
|
||||||
|
"sources": [
|
||||||
|
{
|
||||||
|
"source_id": "langgraph_pypi",
|
||||||
|
"type": "pypi",
|
||||||
|
"url": "https://pypi.org/pypi/langgraph/json",
|
||||||
|
"reference_version": "1.2.6"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"source_id": "langgraph_github_release",
|
||||||
|
"type": "github_release",
|
||||||
|
"url": "https://api.github.com/repos/langchain-ai/langgraph/releases/latest",
|
||||||
|
"reference_version": "1.2.6"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"source_id": "langgraph_docs",
|
||||||
|
"type": "docs",
|
||||||
|
"url": "https://docs.langchain.com/oss/python/langgraph/overview"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"candidate_id": "google_adk_stack",
|
||||||
|
"display_name": "Google Agent Development Kit",
|
||||||
|
"technology_area": "agent_frameworks",
|
||||||
|
"integration_surface": "gemini_enterprise_agent_stack",
|
||||||
|
"awoooi_role": "Gemini/Vertex agent stack watch-only 候選",
|
||||||
|
"evaluation_priority": "p1",
|
||||||
|
"requires_cost_approval": true,
|
||||||
|
"requires_dependency_approval": true,
|
||||||
|
"requires_security_review": true,
|
||||||
|
"sources": [
|
||||||
|
{
|
||||||
|
"source_id": "google_adk_pypi",
|
||||||
|
"type": "pypi",
|
||||||
|
"url": "https://pypi.org/pypi/google-adk/json",
|
||||||
|
"reference_version": "2.3.0"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"source_id": "google_adk_github_release",
|
||||||
|
"type": "github_release",
|
||||||
|
"url": "https://api.github.com/repos/google/adk-python/releases/latest",
|
||||||
|
"reference_version": "v2.3.0"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"source_id": "google_adk_docs",
|
||||||
|
"type": "docs",
|
||||||
|
"url": "https://docs.cloud.google.com/gemini-enterprise-agent-platform/build/adk"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"candidate_id": "microsoft_agent_framework",
|
||||||
|
"display_name": "Microsoft Agent Framework",
|
||||||
|
"technology_area": "agent_frameworks",
|
||||||
|
"integration_surface": "enterprise_mcp_a2a_workflow",
|
||||||
|
"awoooi_role": "MCP/A2A enterprise workflow watch-only 候選",
|
||||||
|
"evaluation_priority": "p1",
|
||||||
|
"requires_cost_approval": true,
|
||||||
|
"requires_dependency_approval": true,
|
||||||
|
"requires_security_review": true,
|
||||||
|
"sources": [
|
||||||
|
{
|
||||||
|
"source_id": "microsoft_agent_framework_github_release",
|
||||||
|
"type": "github_release",
|
||||||
|
"url": "https://api.github.com/repos/microsoft/agent-framework/releases/latest",
|
||||||
|
"reference_version": "dotnet-1.11.0"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"source_id": "microsoft_agent_framework_docs",
|
||||||
|
"type": "docs",
|
||||||
|
"url": "https://learn.microsoft.com/en-us/agent-framework/overview/"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"candidate_id": "crewai_flows",
|
||||||
|
"display_name": "CrewAI Flows + Crews",
|
||||||
|
"technology_area": "agent_frameworks",
|
||||||
|
"integration_surface": "multi_agent_prototype",
|
||||||
|
"awoooi_role": "快速 prototype / non-production 評估候選",
|
||||||
|
"evaluation_priority": "p2",
|
||||||
|
"requires_cost_approval": false,
|
||||||
|
"requires_dependency_approval": true,
|
||||||
|
"requires_security_review": true,
|
||||||
|
"sources": [
|
||||||
|
{
|
||||||
|
"source_id": "crewai_pypi",
|
||||||
|
"type": "pypi",
|
||||||
|
"url": "https://pypi.org/pypi/crewai/json",
|
||||||
|
"reference_version": "1.14.7"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"source_id": "crewai_docs",
|
||||||
|
"type": "docs",
|
||||||
|
"url": "https://docs.crewai.com/"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"candidate_id": "modelcontextprotocol_sdk",
|
||||||
|
"display_name": "Model Context Protocol SDK",
|
||||||
|
"technology_area": "mcp_and_a2a",
|
||||||
|
"integration_surface": "tool_registry_interoperability",
|
||||||
|
"awoooi_role": "read-only tool registry / MCP adapter 候選",
|
||||||
|
"evaluation_priority": "p0",
|
||||||
|
"requires_cost_approval": false,
|
||||||
|
"requires_dependency_approval": true,
|
||||||
|
"requires_security_review": true,
|
||||||
|
"sources": [
|
||||||
|
{
|
||||||
|
"source_id": "mcp_typescript_sdk_npm",
|
||||||
|
"type": "npm",
|
||||||
|
"url": "https://registry.npmjs.org/%40modelcontextprotocol%2Fsdk"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"source_id": "mcp_typescript_sdk_github_release",
|
||||||
|
"type": "github_release",
|
||||||
|
"url": "https://api.github.com/repos/modelcontextprotocol/typescript-sdk/releases/latest"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"source_id": "mcp_typescript_sdk_docs",
|
||||||
|
"type": "docs",
|
||||||
|
"url": "https://github.com/modelcontextprotocol/typescript-sdk"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"candidate_id": "a2a_protocol",
|
||||||
|
"display_name": "Agent2Agent Protocol",
|
||||||
|
"technology_area": "mcp_and_a2a",
|
||||||
|
"integration_surface": "agent_to_agent_interop",
|
||||||
|
"awoooi_role": "跨 Agent 溝通協定 watch-only 候選",
|
||||||
|
"evaluation_priority": "p1",
|
||||||
|
"requires_cost_approval": false,
|
||||||
|
"requires_dependency_approval": true,
|
||||||
|
"requires_security_review": true,
|
||||||
|
"sources": [
|
||||||
|
{
|
||||||
|
"source_id": "a2a_protocol_github_release",
|
||||||
|
"type": "github_release",
|
||||||
|
"url": "https://api.github.com/repos/a2aproject/A2A/releases/latest"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"source_id": "a2a_python_github_release",
|
||||||
|
"type": "github_release",
|
||||||
|
"url": "https://api.github.com/repos/a2aproject/a2a-python/releases/latest"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"source_id": "a2a_protocol_docs",
|
||||||
|
"type": "docs",
|
||||||
|
"url": "https://github.com/a2aproject/A2A"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"candidate_id": "openai_model_platform",
|
||||||
|
"display_name": "OpenAI Model Platform",
|
||||||
|
"technology_area": "model_providers",
|
||||||
|
"integration_surface": "model_capability_cost_routing",
|
||||||
|
"awoooi_role": "模型能力、成本與 routing scorecard 來源",
|
||||||
|
"evaluation_priority": "p0",
|
||||||
|
"requires_cost_approval": true,
|
||||||
|
"requires_dependency_approval": false,
|
||||||
|
"requires_security_review": true,
|
||||||
|
"sources": [
|
||||||
|
{
|
||||||
|
"source_id": "openai_models_docs",
|
||||||
|
"type": "docs",
|
||||||
|
"url": "https://platform.openai.com/docs/models"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"source_id": "openai_python_pypi",
|
||||||
|
"type": "pypi",
|
||||||
|
"url": "https://pypi.org/pypi/openai/json"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"source_id": "openai_node_npm",
|
||||||
|
"type": "npm",
|
||||||
|
"url": "https://registry.npmjs.org/openai"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"candidate_id": "anthropic_claude_platform",
|
||||||
|
"display_name": "Anthropic Claude Platform",
|
||||||
|
"technology_area": "model_providers",
|
||||||
|
"integration_surface": "model_capability_cost_routing",
|
||||||
|
"awoooi_role": "Claude model / coding agent / remediation watch source",
|
||||||
|
"evaluation_priority": "p0",
|
||||||
|
"requires_cost_approval": true,
|
||||||
|
"requires_dependency_approval": false,
|
||||||
|
"requires_security_review": true,
|
||||||
|
"sources": [
|
||||||
|
{
|
||||||
|
"source_id": "anthropic_models_docs",
|
||||||
|
"type": "docs",
|
||||||
|
"url": "https://docs.anthropic.com/en/docs/about-claude/models/overview"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"source_id": "anthropic_sdk_npm",
|
||||||
|
"type": "npm",
|
||||||
|
"url": "https://registry.npmjs.org/%40anthropic-ai%2Fsdk"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"source_id": "claude_agent_sdk_docs",
|
||||||
|
"type": "docs",
|
||||||
|
"url": "https://code.claude.com/docs/en/agent-sdk/overview"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"candidate_id": "google_gemini_platform",
|
||||||
|
"display_name": "Google Gemini Platform",
|
||||||
|
"technology_area": "model_providers",
|
||||||
|
"integration_surface": "model_capability_cost_routing",
|
||||||
|
"awoooi_role": "Gemini model capability / cost watch source",
|
||||||
|
"evaluation_priority": "p1",
|
||||||
|
"requires_cost_approval": true,
|
||||||
|
"requires_dependency_approval": false,
|
||||||
|
"requires_security_review": true,
|
||||||
|
"sources": [
|
||||||
|
{
|
||||||
|
"source_id": "gemini_models_docs",
|
||||||
|
"type": "docs",
|
||||||
|
"url": "https://ai.google.dev/gemini-api/docs/models"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"source_id": "google_genai_pypi",
|
||||||
|
"type": "pypi",
|
||||||
|
"url": "https://pypi.org/pypi/google-genai/json"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"candidate_id": "llamaindex_rag",
|
||||||
|
"display_name": "LlamaIndex",
|
||||||
|
"technology_area": "rag_and_vector",
|
||||||
|
"integration_surface": "rag_indexing_connectors",
|
||||||
|
"awoooi_role": "RAG ingestion / indexing / connector watch source",
|
||||||
|
"evaluation_priority": "p1",
|
||||||
|
"requires_cost_approval": false,
|
||||||
|
"requires_dependency_approval": true,
|
||||||
|
"requires_security_review": true,
|
||||||
|
"sources": [
|
||||||
|
{
|
||||||
|
"source_id": "llama_index_core_pypi",
|
||||||
|
"type": "pypi",
|
||||||
|
"url": "https://pypi.org/pypi/llama-index-core/json"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"source_id": "llama_index_docs",
|
||||||
|
"type": "docs",
|
||||||
|
"url": "https://developers.llamaindex.ai/python/framework/"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"candidate_id": "langchain_runtime",
|
||||||
|
"display_name": "LangChain",
|
||||||
|
"technology_area": "rag_and_vector",
|
||||||
|
"integration_surface": "llm_app_runtime_connectors",
|
||||||
|
"awoooi_role": "LLM app integration connector watch source",
|
||||||
|
"evaluation_priority": "p2",
|
||||||
|
"requires_cost_approval": false,
|
||||||
|
"requires_dependency_approval": true,
|
||||||
|
"requires_security_review": true,
|
||||||
|
"sources": [
|
||||||
|
{
|
||||||
|
"source_id": "langchain_pypi",
|
||||||
|
"type": "pypi",
|
||||||
|
"url": "https://pypi.org/pypi/langchain/json"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"source_id": "langchain_docs",
|
||||||
|
"type": "docs",
|
||||||
|
"url": "https://docs.langchain.com/"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"candidate_id": "pgvector_vector_store",
|
||||||
|
"display_name": "pgvector",
|
||||||
|
"technology_area": "rag_and_vector",
|
||||||
|
"integration_surface": "postgres_vector_index",
|
||||||
|
"awoooi_role": "現有 Postgres/pgvector 能力與版本 freshness 來源",
|
||||||
|
"evaluation_priority": "p1",
|
||||||
|
"requires_cost_approval": false,
|
||||||
|
"requires_dependency_approval": true,
|
||||||
|
"requires_security_review": true,
|
||||||
|
"sources": [
|
||||||
|
{
|
||||||
|
"source_id": "pgvector_github_tags",
|
||||||
|
"type": "github_tags",
|
||||||
|
"url": "https://api.github.com/repos/pgvector/pgvector/tags"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"source_id": "pgvector_docs",
|
||||||
|
"type": "docs",
|
||||||
|
"url": "https://github.com/pgvector/pgvector"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"candidate_id": "qdrant_vector_store",
|
||||||
|
"display_name": "Qdrant",
|
||||||
|
"technology_area": "rag_and_vector",
|
||||||
|
"integration_surface": "dedicated_vector_database",
|
||||||
|
"awoooi_role": "專用 vector DB 候選,只能 sandbox 評估",
|
||||||
|
"evaluation_priority": "p2",
|
||||||
|
"requires_cost_approval": false,
|
||||||
|
"requires_dependency_approval": true,
|
||||||
|
"requires_security_review": true,
|
||||||
|
"sources": [
|
||||||
|
{
|
||||||
|
"source_id": "qdrant_client_pypi",
|
||||||
|
"type": "pypi",
|
||||||
|
"url": "https://pypi.org/pypi/qdrant-client/json"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"source_id": "qdrant_github_release",
|
||||||
|
"type": "github_release",
|
||||||
|
"url": "https://api.github.com/repos/qdrant/qdrant/releases/latest"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"candidate_id": "chromadb_vector_store",
|
||||||
|
"display_name": "ChromaDB",
|
||||||
|
"technology_area": "rag_and_vector",
|
||||||
|
"integration_surface": "local_vector_database",
|
||||||
|
"awoooi_role": "本機 / sandbox vector store 候選",
|
||||||
|
"evaluation_priority": "p3",
|
||||||
|
"requires_cost_approval": false,
|
||||||
|
"requires_dependency_approval": true,
|
||||||
|
"requires_security_review": true,
|
||||||
|
"sources": [
|
||||||
|
{
|
||||||
|
"source_id": "chromadb_pypi",
|
||||||
|
"type": "pypi",
|
||||||
|
"url": "https://pypi.org/pypi/chromadb/json"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"source_id": "chromadb_github_release",
|
||||||
|
"type": "github_release",
|
||||||
|
"url": "https://api.github.com/repos/chroma-core/chroma/releases/latest"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"candidate_id": "ragas_eval",
|
||||||
|
"display_name": "Ragas",
|
||||||
|
"technology_area": "evaluation_and_observability",
|
||||||
|
"integration_surface": "rag_eval_metrics",
|
||||||
|
"awoooi_role": "RAG / LLM app evaluation metrics 候選",
|
||||||
|
"evaluation_priority": "p1",
|
||||||
|
"requires_cost_approval": false,
|
||||||
|
"requires_dependency_approval": true,
|
||||||
|
"requires_security_review": true,
|
||||||
|
"sources": [
|
||||||
|
{
|
||||||
|
"source_id": "ragas_pypi",
|
||||||
|
"type": "pypi",
|
||||||
|
"url": "https://pypi.org/pypi/ragas/json"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"source_id": "ragas_docs",
|
||||||
|
"type": "docs",
|
||||||
|
"url": "https://docs.ragas.io/en/stable/"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"candidate_id": "langfuse_observability",
|
||||||
|
"display_name": "Langfuse",
|
||||||
|
"technology_area": "evaluation_and_observability",
|
||||||
|
"integration_surface": "llm_observability_tracing",
|
||||||
|
"awoooi_role": "LLM trace / prompt / eval observability 候選",
|
||||||
|
"evaluation_priority": "p1",
|
||||||
|
"requires_cost_approval": true,
|
||||||
|
"requires_dependency_approval": true,
|
||||||
|
"requires_security_review": true,
|
||||||
|
"sources": [
|
||||||
|
{
|
||||||
|
"source_id": "langfuse_pypi",
|
||||||
|
"type": "pypi",
|
||||||
|
"url": "https://pypi.org/pypi/langfuse/json"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"source_id": "langfuse_docs",
|
||||||
|
"type": "docs",
|
||||||
|
"url": "https://langfuse.com/docs"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"candidate_id": "huggingface_tgi",
|
||||||
|
"display_name": "Hugging Face Text Generation Inference",
|
||||||
|
"technology_area": "model_serving",
|
||||||
|
"integration_surface": "self_hosted_model_serving",
|
||||||
|
"awoooi_role": "自託管模型 serving 能力與版本 freshness 來源",
|
||||||
|
"evaluation_priority": "p2",
|
||||||
|
"requires_cost_approval": true,
|
||||||
|
"requires_dependency_approval": true,
|
||||||
|
"requires_security_review": true,
|
||||||
|
"sources": [
|
||||||
|
{
|
||||||
|
"source_id": "tgi_github_release",
|
||||||
|
"type": "github_release",
|
||||||
|
"url": "https://api.github.com/repos/huggingface/text-generation-inference/releases/latest"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"source_id": "tgi_docs",
|
||||||
|
"type": "docs",
|
||||||
|
"url": "https://huggingface.co/docs/text-generation-inference/index"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"candidate_id": "vllm_serving",
|
||||||
|
"display_name": "vLLM",
|
||||||
|
"technology_area": "model_serving",
|
||||||
|
"integration_surface": "self_hosted_llm_inference",
|
||||||
|
"awoooi_role": "自託管 LLM inference 候選,需 GPU/成本/安全 gate",
|
||||||
|
"evaluation_priority": "p2",
|
||||||
|
"requires_cost_approval": true,
|
||||||
|
"requires_dependency_approval": true,
|
||||||
|
"requires_security_review": true,
|
||||||
|
"sources": [
|
||||||
|
{
|
||||||
|
"source_id": "vllm_pypi",
|
||||||
|
"type": "pypi",
|
||||||
|
"url": "https://pypi.org/pypi/vllm/json"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"source_id": "vllm_github_release",
|
||||||
|
"type": "github_release",
|
||||||
|
"url": "https://api.github.com/repos/vllm-project/vllm/releases/latest"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"discovery_sources": [
|
||||||
|
{
|
||||||
|
"source_id": "github_ai_agent_discovery",
|
||||||
|
"type": "github_search",
|
||||||
|
"url": "https://api.github.com/search/repositories?q=topic:ai-agent+stars:%3E5000&sort=updated&order=desc"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"source_id": "github_mcp_discovery",
|
||||||
|
"type": "github_search",
|
||||||
|
"url": "https://api.github.com/search/repositories?q=topic:mcp+stars:%3E1000&sort=updated&order=desc"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"source_id": "github_rag_discovery",
|
||||||
|
"type": "github_search",
|
||||||
|
"url": "https://api.github.com/search/repositories?q=topic:rag+stars:%3E3000&sort=updated&order=desc"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
1142
docs/evaluations/ai_technology_watch_report_2026-06-25.json
Normal file
1142
docs/evaluations/ai_technology_watch_report_2026-06-25.json
Normal file
File diff suppressed because it is too large
Load Diff
70
docs/operations/AI-TECHNOLOGY-RADAR-READBACK-2026-06-25.md
Normal file
70
docs/operations/AI-TECHNOLOGY-RADAR-READBACK-2026-06-25.md
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
# AI 技術雷達與滾動更新讀回
|
||||||
|
|
||||||
|
- 產生時間:`2026-06-25T03:56:51.751955+00:00`
|
||||||
|
- 整體治理完成度:`42.2%`
|
||||||
|
- AI 技術雷達來源成功率:`100.0%`
|
||||||
|
- 監控技術項目:`20`
|
||||||
|
- 技術領域:`6`
|
||||||
|
- 官方 / primary sources:`47`
|
||||||
|
- 來源失敗:`0`
|
||||||
|
- 需要審核變更:`0`
|
||||||
|
- 高優先級項目:`14`
|
||||||
|
- 滾動更新狀態:`near_real_time_watch_ready_integration_gated`
|
||||||
|
|
||||||
|
## 技術領域覆蓋
|
||||||
|
|
||||||
|
| 技術領域 | 技術數 | 高優先級 | 需要審核 | 代表技術 |
|
||||||
|
|---|---:|---:|---:|---|
|
||||||
|
| `agent_frameworks` | `6` | `5` | `0` | OpenAI Agents SDK, NVIDIA Nemotron + NeMo Agent Toolkit, LangGraph, Google Agent Development Kit |
|
||||||
|
| `evaluation_and_observability` | `2` | `2` | `0` | Ragas, Langfuse |
|
||||||
|
| `mcp_and_a2a` | `2` | `2` | `0` | Model Context Protocol SDK, Agent2Agent Protocol |
|
||||||
|
| `model_providers` | `3` | `3` | `0` | OpenAI Model Platform, Anthropic Claude Platform, Google Gemini Platform |
|
||||||
|
| `model_serving` | `2` | `0` | `0` | Hugging Face Text Generation Inference, vLLM |
|
||||||
|
| `rag_and_vector` | `5` | `2` | `0` | LlamaIndex, LangChain, pgvector, Qdrant |
|
||||||
|
|
||||||
|
## 高優先級審核佇列
|
||||||
|
|
||||||
|
| 技術 | 領域 | 優先級 | Gate | 下一步 |
|
||||||
|
|---|---|---|---|---|
|
||||||
|
|
||||||
|
## Agent 專業分工
|
||||||
|
|
||||||
|
| Agent | 專業角色 | 自動化範圍 | 需要審核的邊界 |
|
||||||
|
|---|---|---|---|
|
||||||
|
| OpenClaw | 生產決策仲裁者、風險分級與最後 policy guard | 維持現有 production baseline、讀取 replay / shadow 評分、拒絕無證據替換 | 任何取代、降級、生產路由切換都必須通過 replay / shadow / canary 與人工批准。 |
|
||||||
|
| NemoTron | 離線回放評估者、模型能力比較、合約輸出 smoke gate | 只讀 request pack、比對候選輸出、產生 replay scorecard 草稿 | 不得自行呼叫外部 NIM/API、不得讀 labels 作答、不得進生產路由。 |
|
||||||
|
| Hermes | 知識管理、RAG 整理、報告草稿與長期技能庫維護 | 整理 primary source 摘要、建立 no-send 日週月報、準備人審包 | 不得同步 raw chat history、不得保存 secret、不得直接發 Telegram live report。 |
|
||||||
|
| MarketRadar | AI 技術市場雷達、版本監控、來源失敗偵測 | 每 6 小時只讀 primary sources、產生 freshness / review queue | 不得自動新增 SDK、不得自動修改 provider route 或 workflow 行為。 |
|
||||||
|
| Critic / Reviewer | 獨立審核、反例檢查、整合風險評分 | 檢查政策旗標、來源可靠性、成本與資安風險 | 只能輸出 blocked / candidate / owner_review,不得直接執行寫入。 |
|
||||||
|
|
||||||
|
## 滾動更新控制
|
||||||
|
|
||||||
|
| 節奏 | Agent 可自動做什麼 | 輸出 | Gate |
|
||||||
|
|---|---|---|---|
|
||||||
|
| 每 6 小時 | 讀取官方文件、PyPI、npm、GitHub release、primary source hash。 | AI 技術 watch report、來源失敗清單、review queue。 | `read_only_only` |
|
||||||
|
| 每日 | 依 business applicability、成本、依賴、資安、AWOOOI fit 分類。 | 日報摘要與中低風險自動處理建議。 | `no_send_report_until_delivery_gate` |
|
||||||
|
| 每週 | 刷新 scorecard,決定 sandbox / replay / adapter design 優先級。 | 週報、優先序、候選整合審查包。 | `scorecard_required_before_replay` |
|
||||||
|
| 每月 | 彙整趨勢,提出 roadmap / watch-only / retire 建議。 | 月報與策略審核包。 | `human_review_for_strategy_or_production_change` |
|
||||||
|
|
||||||
|
## 優先工作清單
|
||||||
|
|
||||||
|
| 順序 | 工作 | 優先級 | 自動化模式 | 完成定義 |
|
||||||
|
|---:|---|---|---|---|
|
||||||
|
| 1 | AI 技術雷達 primary source 監控產品化 | `P0` | `agent_auto_read_only` | API、snapshot、Markdown、schema、測試與 production readback 都能顯示技術領域、來源與 Gate。 |
|
||||||
|
| 2 | 近即時版本 / release / docs 變更偵測 | `P0` | `agent_auto_schedule_read_only` | 每 6 小時可跑 watch;失敗來源會進日報,不會自動整合。 |
|
||||||
|
| 3 | OpenClaw / Hermes / NemoTron / MarketRadar 專業分工與成長紀錄 | `P0` | `agent_auto_read_model_human_review_for_write` | 每個 Agent 的角色、輸出、學習寫回與限制都能被前端讀回。 |
|
||||||
|
| 4 | AI 技術 scorecard 與 sandbox / replay 優先級 | `P1` | `agent_propose_owner_review` | 高優先級變更先進 scorecard,再進 no-cost/no-write sandbox 或 replay 計畫。 |
|
||||||
|
| 5 | Telegram Bot 報告與高風險審核橋接 | `P1` | `blocked_until_telegram_send_gate` | 低中風險只告警回報;高風險需 owner approval 後才可發送或執行。 |
|
||||||
|
| 6 | 新 AI 技術探索與 watchlist 擴充 | `P2` | `agent_auto_discover_human_classify` | GitHub topic / package registry / 官方 blog 可提出候選,但加入正式 watchlist 前需審核。 |
|
||||||
|
|
||||||
|
## 仍被 Gate 擋下
|
||||||
|
|
||||||
|
- `sdk_installation_approved=false`
|
||||||
|
- `paid_api_calls_approved=false`
|
||||||
|
- `production_routing_approved=false`
|
||||||
|
- `telegram_send_approved=false`
|
||||||
|
- `model_provider_switch_approved=false`
|
||||||
|
- `host_write_approved=false`
|
||||||
|
- `openclaw_replacement_approved=false`
|
||||||
|
- `replay_shadow_canary_gate_required=true`
|
||||||
|
- `cost_and_data_boundary_review_required=true`
|
||||||
70
docs/operations/AI-TECHNOLOGY-RADAR-READBACK.md
Normal file
70
docs/operations/AI-TECHNOLOGY-RADAR-READBACK.md
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
# AI 技術雷達與滾動更新讀回
|
||||||
|
|
||||||
|
- 產生時間:`2026-06-25T03:56:51.751955+00:00`
|
||||||
|
- 整體治理完成度:`42.2%`
|
||||||
|
- AI 技術雷達來源成功率:`100.0%`
|
||||||
|
- 監控技術項目:`20`
|
||||||
|
- 技術領域:`6`
|
||||||
|
- 官方 / primary sources:`47`
|
||||||
|
- 來源失敗:`0`
|
||||||
|
- 需要審核變更:`0`
|
||||||
|
- 高優先級項目:`14`
|
||||||
|
- 滾動更新狀態:`near_real_time_watch_ready_integration_gated`
|
||||||
|
|
||||||
|
## 技術領域覆蓋
|
||||||
|
|
||||||
|
| 技術領域 | 技術數 | 高優先級 | 需要審核 | 代表技術 |
|
||||||
|
|---|---:|---:|---:|---|
|
||||||
|
| `agent_frameworks` | `6` | `5` | `0` | OpenAI Agents SDK, NVIDIA Nemotron + NeMo Agent Toolkit, LangGraph, Google Agent Development Kit |
|
||||||
|
| `evaluation_and_observability` | `2` | `2` | `0` | Ragas, Langfuse |
|
||||||
|
| `mcp_and_a2a` | `2` | `2` | `0` | Model Context Protocol SDK, Agent2Agent Protocol |
|
||||||
|
| `model_providers` | `3` | `3` | `0` | OpenAI Model Platform, Anthropic Claude Platform, Google Gemini Platform |
|
||||||
|
| `model_serving` | `2` | `0` | `0` | Hugging Face Text Generation Inference, vLLM |
|
||||||
|
| `rag_and_vector` | `5` | `2` | `0` | LlamaIndex, LangChain, pgvector, Qdrant |
|
||||||
|
|
||||||
|
## 高優先級審核佇列
|
||||||
|
|
||||||
|
| 技術 | 領域 | 優先級 | Gate | 下一步 |
|
||||||
|
|---|---|---|---|---|
|
||||||
|
|
||||||
|
## Agent 專業分工
|
||||||
|
|
||||||
|
| Agent | 專業角色 | 自動化範圍 | 需要審核的邊界 |
|
||||||
|
|---|---|---|---|
|
||||||
|
| OpenClaw | 生產決策仲裁者、風險分級與最後 policy guard | 維持現有 production baseline、讀取 replay / shadow 評分、拒絕無證據替換 | 任何取代、降級、生產路由切換都必須通過 replay / shadow / canary 與人工批准。 |
|
||||||
|
| NemoTron | 離線回放評估者、模型能力比較、合約輸出 smoke gate | 只讀 request pack、比對候選輸出、產生 replay scorecard 草稿 | 不得自行呼叫外部 NIM/API、不得讀 labels 作答、不得進生產路由。 |
|
||||||
|
| Hermes | 知識管理、RAG 整理、報告草稿與長期技能庫維護 | 整理 primary source 摘要、建立 no-send 日週月報、準備人審包 | 不得同步 raw chat history、不得保存 secret、不得直接發 Telegram live report。 |
|
||||||
|
| MarketRadar | AI 技術市場雷達、版本監控、來源失敗偵測 | 每 6 小時只讀 primary sources、產生 freshness / review queue | 不得自動新增 SDK、不得自動修改 provider route 或 workflow 行為。 |
|
||||||
|
| Critic / Reviewer | 獨立審核、反例檢查、整合風險評分 | 檢查政策旗標、來源可靠性、成本與資安風險 | 只能輸出 blocked / candidate / owner_review,不得直接執行寫入。 |
|
||||||
|
|
||||||
|
## 滾動更新控制
|
||||||
|
|
||||||
|
| 節奏 | Agent 可自動做什麼 | 輸出 | Gate |
|
||||||
|
|---|---|---|---|
|
||||||
|
| 每 6 小時 | 讀取官方文件、PyPI、npm、GitHub release、primary source hash。 | AI 技術 watch report、來源失敗清單、review queue。 | `read_only_only` |
|
||||||
|
| 每日 | 依 business applicability、成本、依賴、資安、AWOOOI fit 分類。 | 日報摘要與中低風險自動處理建議。 | `no_send_report_until_delivery_gate` |
|
||||||
|
| 每週 | 刷新 scorecard,決定 sandbox / replay / adapter design 優先級。 | 週報、優先序、候選整合審查包。 | `scorecard_required_before_replay` |
|
||||||
|
| 每月 | 彙整趨勢,提出 roadmap / watch-only / retire 建議。 | 月報與策略審核包。 | `human_review_for_strategy_or_production_change` |
|
||||||
|
|
||||||
|
## 優先工作清單
|
||||||
|
|
||||||
|
| 順序 | 工作 | 優先級 | 自動化模式 | 完成定義 |
|
||||||
|
|---:|---|---|---|---|
|
||||||
|
| 1 | AI 技術雷達 primary source 監控產品化 | `P0` | `agent_auto_read_only` | API、snapshot、Markdown、schema、測試與 production readback 都能顯示技術領域、來源與 Gate。 |
|
||||||
|
| 2 | 近即時版本 / release / docs 變更偵測 | `P0` | `agent_auto_schedule_read_only` | 每 6 小時可跑 watch;失敗來源會進日報,不會自動整合。 |
|
||||||
|
| 3 | OpenClaw / Hermes / NemoTron / MarketRadar 專業分工與成長紀錄 | `P0` | `agent_auto_read_model_human_review_for_write` | 每個 Agent 的角色、輸出、學習寫回與限制都能被前端讀回。 |
|
||||||
|
| 4 | AI 技術 scorecard 與 sandbox / replay 優先級 | `P1` | `agent_propose_owner_review` | 高優先級變更先進 scorecard,再進 no-cost/no-write sandbox 或 replay 計畫。 |
|
||||||
|
| 5 | Telegram Bot 報告與高風險審核橋接 | `P1` | `blocked_until_telegram_send_gate` | 低中風險只告警回報;高風險需 owner approval 後才可發送或執行。 |
|
||||||
|
| 6 | 新 AI 技術探索與 watchlist 擴充 | `P2` | `agent_auto_discover_human_classify` | GitHub topic / package registry / 官方 blog 可提出候選,但加入正式 watchlist 前需審核。 |
|
||||||
|
|
||||||
|
## 仍被 Gate 擋下
|
||||||
|
|
||||||
|
- `sdk_installation_approved=false`
|
||||||
|
- `paid_api_calls_approved=false`
|
||||||
|
- `production_routing_approved=false`
|
||||||
|
- `telegram_send_approved=false`
|
||||||
|
- `model_provider_switch_approved=false`
|
||||||
|
- `host_write_approved=false`
|
||||||
|
- `openclaw_replacement_approved=false`
|
||||||
|
- `replay_shadow_canary_gate_required=true`
|
||||||
|
- `cost_and_data_boundary_review_required=true`
|
||||||
496
docs/operations/ai-technology-radar-readback.snapshot.json
Normal file
496
docs/operations/ai-technology-radar-readback.snapshot.json
Normal file
@@ -0,0 +1,496 @@
|
|||||||
|
{
|
||||||
|
"blocked_gates": [
|
||||||
|
"sdk_installation_approved=false",
|
||||||
|
"paid_api_calls_approved=false",
|
||||||
|
"production_routing_approved=false",
|
||||||
|
"telegram_send_approved=false",
|
||||||
|
"model_provider_switch_approved=false",
|
||||||
|
"host_write_approved=false",
|
||||||
|
"openclaw_replacement_approved=false",
|
||||||
|
"replay_shadow_canary_gate_required=true",
|
||||||
|
"cost_and_data_boundary_review_required=true"
|
||||||
|
],
|
||||||
|
"generated_at": "2026-06-25T03:56:51.751955+00:00",
|
||||||
|
"high_priority_review_queue": [],
|
||||||
|
"integration_candidates": [
|
||||||
|
{
|
||||||
|
"awoooi_role": "協調者、handoff、tool tracing、guardrail 候選",
|
||||||
|
"changed": false,
|
||||||
|
"decision": "watch_only_no_change",
|
||||||
|
"display_name": "OpenAI Agents SDK",
|
||||||
|
"integration_surface": "agent_handoff_tracing_guardrails",
|
||||||
|
"recommended_actions": [
|
||||||
|
"keep_watch_only_status"
|
||||||
|
],
|
||||||
|
"technology_area": "agent_frameworks",
|
||||||
|
"technology_id": "openai_agents_sdk"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"awoooi_role": "NemoTron replay / evaluator / synthetic data gate",
|
||||||
|
"changed": false,
|
||||||
|
"decision": "watch_only_no_change",
|
||||||
|
"display_name": "NVIDIA Nemotron + NeMo Agent Toolkit",
|
||||||
|
"integration_surface": "offline_replay_evaluator_smoke_gate",
|
||||||
|
"recommended_actions": [
|
||||||
|
"keep_watch_only_status"
|
||||||
|
],
|
||||||
|
"technology_area": "agent_frameworks",
|
||||||
|
"technology_id": "nvidia_nemotron_nemo"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"awoooi_role": "事件處理與可恢復 workflow kernel 候選",
|
||||||
|
"changed": false,
|
||||||
|
"decision": "watch_only_no_change",
|
||||||
|
"display_name": "LangGraph",
|
||||||
|
"integration_surface": "durable_workflow_human_in_loop",
|
||||||
|
"recommended_actions": [
|
||||||
|
"keep_watch_only_status"
|
||||||
|
],
|
||||||
|
"technology_area": "agent_frameworks",
|
||||||
|
"technology_id": "langgraph_runtime"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"awoooi_role": "Gemini/Vertex agent stack watch-only 候選",
|
||||||
|
"changed": false,
|
||||||
|
"decision": "watch_only_no_change",
|
||||||
|
"display_name": "Google Agent Development Kit",
|
||||||
|
"integration_surface": "gemini_enterprise_agent_stack",
|
||||||
|
"recommended_actions": [
|
||||||
|
"keep_watch_only_status"
|
||||||
|
],
|
||||||
|
"technology_area": "agent_frameworks",
|
||||||
|
"technology_id": "google_adk_stack"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"awoooi_role": "MCP/A2A enterprise workflow watch-only 候選",
|
||||||
|
"changed": false,
|
||||||
|
"decision": "watch_only_no_change",
|
||||||
|
"display_name": "Microsoft Agent Framework",
|
||||||
|
"integration_surface": "enterprise_mcp_a2a_workflow",
|
||||||
|
"recommended_actions": [
|
||||||
|
"keep_watch_only_status"
|
||||||
|
],
|
||||||
|
"technology_area": "agent_frameworks",
|
||||||
|
"technology_id": "microsoft_agent_framework"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"awoooi_role": "快速 prototype / non-production 評估候選",
|
||||||
|
"changed": false,
|
||||||
|
"decision": "watch_only_no_change",
|
||||||
|
"display_name": "CrewAI Flows + Crews",
|
||||||
|
"integration_surface": "multi_agent_prototype",
|
||||||
|
"recommended_actions": [
|
||||||
|
"keep_watch_only_status"
|
||||||
|
],
|
||||||
|
"technology_area": "agent_frameworks",
|
||||||
|
"technology_id": "crewai_flows"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"awoooi_role": "read-only tool registry / MCP adapter 候選",
|
||||||
|
"changed": false,
|
||||||
|
"decision": "watch_only_no_change",
|
||||||
|
"display_name": "Model Context Protocol SDK",
|
||||||
|
"integration_surface": "tool_registry_interoperability",
|
||||||
|
"recommended_actions": [
|
||||||
|
"keep_watch_only_status"
|
||||||
|
],
|
||||||
|
"technology_area": "mcp_and_a2a",
|
||||||
|
"technology_id": "modelcontextprotocol_sdk"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"awoooi_role": "跨 Agent 溝通協定 watch-only 候選",
|
||||||
|
"changed": false,
|
||||||
|
"decision": "watch_only_no_change",
|
||||||
|
"display_name": "Agent2Agent Protocol",
|
||||||
|
"integration_surface": "agent_to_agent_interop",
|
||||||
|
"recommended_actions": [
|
||||||
|
"keep_watch_only_status"
|
||||||
|
],
|
||||||
|
"technology_area": "mcp_and_a2a",
|
||||||
|
"technology_id": "a2a_protocol"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"awoooi_role": "模型能力、成本與 routing scorecard 來源",
|
||||||
|
"changed": false,
|
||||||
|
"decision": "watch_only_no_change",
|
||||||
|
"display_name": "OpenAI Model Platform",
|
||||||
|
"integration_surface": "model_capability_cost_routing",
|
||||||
|
"recommended_actions": [
|
||||||
|
"keep_watch_only_status"
|
||||||
|
],
|
||||||
|
"technology_area": "model_providers",
|
||||||
|
"technology_id": "openai_model_platform"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"awoooi_role": "Claude model / coding agent / remediation watch source",
|
||||||
|
"changed": false,
|
||||||
|
"decision": "watch_only_no_change",
|
||||||
|
"display_name": "Anthropic Claude Platform",
|
||||||
|
"integration_surface": "model_capability_cost_routing",
|
||||||
|
"recommended_actions": [
|
||||||
|
"keep_watch_only_status"
|
||||||
|
],
|
||||||
|
"technology_area": "model_providers",
|
||||||
|
"technology_id": "anthropic_claude_platform"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"awoooi_role": "Gemini model capability / cost watch source",
|
||||||
|
"changed": false,
|
||||||
|
"decision": "watch_only_no_change",
|
||||||
|
"display_name": "Google Gemini Platform",
|
||||||
|
"integration_surface": "model_capability_cost_routing",
|
||||||
|
"recommended_actions": [
|
||||||
|
"keep_watch_only_status"
|
||||||
|
],
|
||||||
|
"technology_area": "model_providers",
|
||||||
|
"technology_id": "google_gemini_platform"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"awoooi_role": "RAG ingestion / indexing / connector watch source",
|
||||||
|
"changed": false,
|
||||||
|
"decision": "watch_only_no_change",
|
||||||
|
"display_name": "LlamaIndex",
|
||||||
|
"integration_surface": "rag_indexing_connectors",
|
||||||
|
"recommended_actions": [
|
||||||
|
"keep_watch_only_status"
|
||||||
|
],
|
||||||
|
"technology_area": "rag_and_vector",
|
||||||
|
"technology_id": "llamaindex_rag"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"awoooi_role": "LLM app integration connector watch source",
|
||||||
|
"changed": false,
|
||||||
|
"decision": "watch_only_no_change",
|
||||||
|
"display_name": "LangChain",
|
||||||
|
"integration_surface": "llm_app_runtime_connectors",
|
||||||
|
"recommended_actions": [
|
||||||
|
"keep_watch_only_status"
|
||||||
|
],
|
||||||
|
"technology_area": "rag_and_vector",
|
||||||
|
"technology_id": "langchain_runtime"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"awoooi_role": "現有 Postgres/pgvector 能力與版本 freshness 來源",
|
||||||
|
"changed": false,
|
||||||
|
"decision": "watch_only_no_change",
|
||||||
|
"display_name": "pgvector",
|
||||||
|
"integration_surface": "postgres_vector_index",
|
||||||
|
"recommended_actions": [
|
||||||
|
"keep_watch_only_status"
|
||||||
|
],
|
||||||
|
"technology_area": "rag_and_vector",
|
||||||
|
"technology_id": "pgvector_vector_store"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"awoooi_role": "專用 vector DB 候選,只能 sandbox 評估",
|
||||||
|
"changed": false,
|
||||||
|
"decision": "watch_only_no_change",
|
||||||
|
"display_name": "Qdrant",
|
||||||
|
"integration_surface": "dedicated_vector_database",
|
||||||
|
"recommended_actions": [
|
||||||
|
"keep_watch_only_status"
|
||||||
|
],
|
||||||
|
"technology_area": "rag_and_vector",
|
||||||
|
"technology_id": "qdrant_vector_store"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"awoooi_role": "本機 / sandbox vector store 候選",
|
||||||
|
"changed": false,
|
||||||
|
"decision": "watch_only_no_change",
|
||||||
|
"display_name": "ChromaDB",
|
||||||
|
"integration_surface": "local_vector_database",
|
||||||
|
"recommended_actions": [
|
||||||
|
"keep_watch_only_status"
|
||||||
|
],
|
||||||
|
"technology_area": "rag_and_vector",
|
||||||
|
"technology_id": "chromadb_vector_store"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"awoooi_role": "RAG / LLM app evaluation metrics 候選",
|
||||||
|
"changed": false,
|
||||||
|
"decision": "watch_only_no_change",
|
||||||
|
"display_name": "Ragas",
|
||||||
|
"integration_surface": "rag_eval_metrics",
|
||||||
|
"recommended_actions": [
|
||||||
|
"keep_watch_only_status"
|
||||||
|
],
|
||||||
|
"technology_area": "evaluation_and_observability",
|
||||||
|
"technology_id": "ragas_eval"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"awoooi_role": "LLM trace / prompt / eval observability 候選",
|
||||||
|
"changed": false,
|
||||||
|
"decision": "watch_only_no_change",
|
||||||
|
"display_name": "Langfuse",
|
||||||
|
"integration_surface": "llm_observability_tracing",
|
||||||
|
"recommended_actions": [
|
||||||
|
"keep_watch_only_status"
|
||||||
|
],
|
||||||
|
"technology_area": "evaluation_and_observability",
|
||||||
|
"technology_id": "langfuse_observability"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"awoooi_role": "自託管模型 serving 能力與版本 freshness 來源",
|
||||||
|
"changed": false,
|
||||||
|
"decision": "watch_only_no_change",
|
||||||
|
"display_name": "Hugging Face Text Generation Inference",
|
||||||
|
"integration_surface": "self_hosted_model_serving",
|
||||||
|
"recommended_actions": [
|
||||||
|
"keep_watch_only_status"
|
||||||
|
],
|
||||||
|
"technology_area": "model_serving",
|
||||||
|
"technology_id": "huggingface_tgi"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"awoooi_role": "自託管 LLM inference 候選,需 GPU/成本/安全 gate",
|
||||||
|
"changed": false,
|
||||||
|
"decision": "watch_only_no_change",
|
||||||
|
"display_name": "vLLM",
|
||||||
|
"integration_surface": "self_hosted_llm_inference",
|
||||||
|
"recommended_actions": [
|
||||||
|
"keep_watch_only_status"
|
||||||
|
],
|
||||||
|
"technology_area": "model_serving",
|
||||||
|
"technology_id": "vllm_serving"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"policy": {
|
||||||
|
"host_write_approved": false,
|
||||||
|
"model_provider_switch_approved": false,
|
||||||
|
"openclaw_replacement_approved": false,
|
||||||
|
"paid_api_calls_approved": false,
|
||||||
|
"production_routing_approved": false,
|
||||||
|
"raw_chat_history_synced": false,
|
||||||
|
"read_only": true,
|
||||||
|
"sdk_installation_approved": false,
|
||||||
|
"telegram_send_approved": false
|
||||||
|
},
|
||||||
|
"priority_workplan": [
|
||||||
|
{
|
||||||
|
"automation_mode": "agent_auto_read_only",
|
||||||
|
"done_definition": "API、snapshot、Markdown、schema、測試與 production readback 都能顯示技術領域、來源與 Gate。",
|
||||||
|
"order": 1,
|
||||||
|
"priority": "P0",
|
||||||
|
"work_item": "AI 技術雷達 primary source 監控產品化"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"automation_mode": "agent_auto_schedule_read_only",
|
||||||
|
"done_definition": "每 6 小時可跑 watch;失敗來源會進日報,不會自動整合。",
|
||||||
|
"order": 2,
|
||||||
|
"priority": "P0",
|
||||||
|
"work_item": "近即時版本 / release / docs 變更偵測"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"automation_mode": "agent_auto_read_model_human_review_for_write",
|
||||||
|
"done_definition": "每個 Agent 的角色、輸出、學習寫回與限制都能被前端讀回。",
|
||||||
|
"order": 3,
|
||||||
|
"priority": "P0",
|
||||||
|
"work_item": "OpenClaw / Hermes / NemoTron / MarketRadar 專業分工與成長紀錄"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"automation_mode": "agent_propose_owner_review",
|
||||||
|
"done_definition": "高優先級變更先進 scorecard,再進 no-cost/no-write sandbox 或 replay 計畫。",
|
||||||
|
"order": 4,
|
||||||
|
"priority": "P1",
|
||||||
|
"work_item": "AI 技術 scorecard 與 sandbox / replay 優先級"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"automation_mode": "blocked_until_telegram_send_gate",
|
||||||
|
"done_definition": "低中風險只告警回報;高風險需 owner approval 後才可發送或執行。",
|
||||||
|
"order": 5,
|
||||||
|
"priority": "P1",
|
||||||
|
"work_item": "Telegram Bot 報告與高風險審核橋接"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"automation_mode": "agent_auto_discover_human_classify",
|
||||||
|
"done_definition": "GitHub topic / package registry / 官方 blog 可提出候選,但加入正式 watchlist 前需審核。",
|
||||||
|
"order": 6,
|
||||||
|
"priority": "P2",
|
||||||
|
"work_item": "新 AI 技術探索與 watchlist 擴充"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"professional_agent_roles": [
|
||||||
|
{
|
||||||
|
"agent": "OpenClaw",
|
||||||
|
"auto_scope": "維持現有 production baseline、讀取 replay / shadow 評分、拒絕無證據替換",
|
||||||
|
"professional_role": "生產決策仲裁者、風險分級與最後 policy guard",
|
||||||
|
"review_boundary": "任何取代、降級、生產路由切換都必須通過 replay / shadow / canary 與人工批准。"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"agent": "NemoTron",
|
||||||
|
"auto_scope": "只讀 request pack、比對候選輸出、產生 replay scorecard 草稿",
|
||||||
|
"professional_role": "離線回放評估者、模型能力比較、合約輸出 smoke gate",
|
||||||
|
"review_boundary": "不得自行呼叫外部 NIM/API、不得讀 labels 作答、不得進生產路由。"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"agent": "Hermes",
|
||||||
|
"auto_scope": "整理 primary source 摘要、建立 no-send 日週月報、準備人審包",
|
||||||
|
"professional_role": "知識管理、RAG 整理、報告草稿與長期技能庫維護",
|
||||||
|
"review_boundary": "不得同步 raw chat history、不得保存 secret、不得直接發 Telegram live report。"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"agent": "MarketRadar",
|
||||||
|
"auto_scope": "每 6 小時只讀 primary sources、產生 freshness / review queue",
|
||||||
|
"professional_role": "AI 技術市場雷達、版本監控、來源失敗偵測",
|
||||||
|
"review_boundary": "不得自動新增 SDK、不得自動修改 provider route 或 workflow 行為。"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"agent": "Critic / Reviewer",
|
||||||
|
"auto_scope": "檢查政策旗標、來源可靠性、成本與資安風險",
|
||||||
|
"professional_role": "獨立審核、反例檢查、整合風險評分",
|
||||||
|
"review_boundary": "只能輸出 blocked / candidate / owner_review,不得直接執行寫入。"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"report_contract": {
|
||||||
|
"agent_auto_allowed_for": [
|
||||||
|
"官方來源只讀監控",
|
||||||
|
"版本與文件 hash 比對",
|
||||||
|
"審核佇列分類",
|
||||||
|
"繁中 no-send 報告草稿",
|
||||||
|
"離線 replay fixture 準備",
|
||||||
|
"低風險文件與讀回 snapshot 更新提案"
|
||||||
|
],
|
||||||
|
"api_endpoint": "/api/v1/agents/ai-technology-radar-readback",
|
||||||
|
"daily": "每日彙整變更、來源失敗、審核佇列與可自動處理項目。",
|
||||||
|
"frontend_target": "/zh-TW/governance?tab=agent-market",
|
||||||
|
"human_review_required_for": [
|
||||||
|
"新 SDK / package / MCP server 安裝",
|
||||||
|
"付費 API 或 token 上限變更",
|
||||||
|
"模型 provider / 生產路由切換",
|
||||||
|
"Telegram Bot 即時發送或審批按鈕策略變更",
|
||||||
|
"主機、K8s、workflow、Nginx、secret 或資料層寫入",
|
||||||
|
"OpenClaw 生產決策核心替換、拆分或降級"
|
||||||
|
],
|
||||||
|
"monthly": "每月進行策略 review,決定納入 roadmap、維持 watch-only 或移出監控。",
|
||||||
|
"near_real_time": "每 6 小時讀取 primary sources,偵測主流 AI 技術版本、文件與 release 變更。",
|
||||||
|
"schedule_cron_utc": "0 */6 * * *",
|
||||||
|
"schedule_enabled": true,
|
||||||
|
"schedule_workflow": ".gitea/workflows/ai-technology-watch.yaml",
|
||||||
|
"weekly": "每週做技術 scorecard,決定 sandbox / replay / adapter design 優先級。"
|
||||||
|
},
|
||||||
|
"rolling_update_controls": [
|
||||||
|
{
|
||||||
|
"agent_auto_action": "讀取官方文件、PyPI、npm、GitHub release、primary source hash。",
|
||||||
|
"cadence": "每 6 小時",
|
||||||
|
"cadence_source": "每 6 小時執行一次只讀 primary-source 檢查,偵測主流 AI 技術版本、文件與 release 變更。",
|
||||||
|
"gate": "read_only_only",
|
||||||
|
"output": "AI 技術 watch report、來源失敗清單、review queue。"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"agent_auto_action": "依 business applicability、成本、依賴、資安、AWOOOI fit 分類。",
|
||||||
|
"cadence": "每日",
|
||||||
|
"cadence_source": "每日彙整變更技術,依商業適用性、依賴風險、成本風險與資安風險分組。",
|
||||||
|
"gate": "no_send_report_until_delivery_gate",
|
||||||
|
"output": "日報摘要與中低風險自動處理建議。"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"agent_auto_action": "刷新 scorecard,決定 sandbox / replay / adapter design 優先級。",
|
||||||
|
"cadence": "每週",
|
||||||
|
"cadence_source": "每週刷新技術 scorecard,判斷是否值得進入 sandbox、offline replay 或 adapter design。",
|
||||||
|
"gate": "scorecard_required_before_replay",
|
||||||
|
"output": "週報、優先序、候選整合審查包。"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"agent_auto_action": "彙整趨勢,提出 roadmap / watch-only / retire 建議。",
|
||||||
|
"cadence": "每月",
|
||||||
|
"cadence_source": "每月策略檢討,決定技術應納入 roadmap、維持 watch-only 或從監控清單移除。",
|
||||||
|
"gate": "human_review_for_strategy_or_production_change",
|
||||||
|
"output": "月報與策略審核包。"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"schema_version": "ai_technology_radar_readback_v1",
|
||||||
|
"source_scope": {
|
||||||
|
"agent_market_radar_readback": "docs/operations/ai-agent-market-radar-readback.snapshot.json",
|
||||||
|
"gitea_main_evidence_basis_commit": "683428bd",
|
||||||
|
"scope_note": "本讀回只整合已提交的只讀來源監控、AI Agent 市場雷達與治理 gate;不包含 raw chat history、secret、session 或本機工作視窗內容。",
|
||||||
|
"technology_source_registry": "docs/ai/ai-technology-watch-sources.v1.json",
|
||||||
|
"technology_watch_report": "docs/evaluations/ai_technology_watch_report_2026-06-25.json"
|
||||||
|
},
|
||||||
|
"summary": {
|
||||||
|
"ai_technology_radar_completion_percent": 100.0,
|
||||||
|
"changed_technologies": 0,
|
||||||
|
"high_priority_count": 14,
|
||||||
|
"overall_completion_percent": 42.2,
|
||||||
|
"review_queue_count": 0,
|
||||||
|
"rolling_update_status": "near_real_time_watch_ready_integration_gated",
|
||||||
|
"source_count": 47,
|
||||||
|
"source_failures": 0,
|
||||||
|
"technology_area_count": 6,
|
||||||
|
"technology_count": 20
|
||||||
|
},
|
||||||
|
"technology_area_counts": {
|
||||||
|
"agent_frameworks": 6,
|
||||||
|
"evaluation_and_observability": 2,
|
||||||
|
"mcp_and_a2a": 2,
|
||||||
|
"model_providers": 3,
|
||||||
|
"model_serving": 2,
|
||||||
|
"rag_and_vector": 5
|
||||||
|
},
|
||||||
|
"technology_domains": [
|
||||||
|
{
|
||||||
|
"changed_count": 0,
|
||||||
|
"high_priority_count": 5,
|
||||||
|
"representative_technologies": [
|
||||||
|
"OpenAI Agents SDK",
|
||||||
|
"NVIDIA Nemotron + NeMo Agent Toolkit",
|
||||||
|
"LangGraph",
|
||||||
|
"Google Agent Development Kit"
|
||||||
|
],
|
||||||
|
"technology_area": "agent_frameworks",
|
||||||
|
"technology_count": 6
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"changed_count": 0,
|
||||||
|
"high_priority_count": 2,
|
||||||
|
"representative_technologies": [
|
||||||
|
"Ragas",
|
||||||
|
"Langfuse"
|
||||||
|
],
|
||||||
|
"technology_area": "evaluation_and_observability",
|
||||||
|
"technology_count": 2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"changed_count": 0,
|
||||||
|
"high_priority_count": 2,
|
||||||
|
"representative_technologies": [
|
||||||
|
"Model Context Protocol SDK",
|
||||||
|
"Agent2Agent Protocol"
|
||||||
|
],
|
||||||
|
"technology_area": "mcp_and_a2a",
|
||||||
|
"technology_count": 2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"changed_count": 0,
|
||||||
|
"high_priority_count": 3,
|
||||||
|
"representative_technologies": [
|
||||||
|
"OpenAI Model Platform",
|
||||||
|
"Anthropic Claude Platform",
|
||||||
|
"Google Gemini Platform"
|
||||||
|
],
|
||||||
|
"technology_area": "model_providers",
|
||||||
|
"technology_count": 3
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"changed_count": 0,
|
||||||
|
"high_priority_count": 0,
|
||||||
|
"representative_technologies": [
|
||||||
|
"Hugging Face Text Generation Inference",
|
||||||
|
"vLLM"
|
||||||
|
],
|
||||||
|
"technology_area": "model_serving",
|
||||||
|
"technology_count": 2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"changed_count": 0,
|
||||||
|
"high_priority_count": 2,
|
||||||
|
"representative_technologies": [
|
||||||
|
"LlamaIndex",
|
||||||
|
"LangChain",
|
||||||
|
"pgvector",
|
||||||
|
"Qdrant"
|
||||||
|
],
|
||||||
|
"technology_area": "rag_and_vector",
|
||||||
|
"technology_count": 5
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
127
docs/schemas/ai_technology_radar_readback_v1.schema.json
Normal file
127
docs/schemas/ai_technology_radar_readback_v1.schema.json
Normal file
@@ -0,0 +1,127 @@
|
|||||||
|
{
|
||||||
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
|
"$id": "urn:awoooi:ai-technology-radar-readback-v1",
|
||||||
|
"title": "AWOOOI AI 技術雷達產品讀回快照 (v1)",
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"schema_version",
|
||||||
|
"generated_at",
|
||||||
|
"source_scope",
|
||||||
|
"summary",
|
||||||
|
"policy",
|
||||||
|
"technology_area_counts",
|
||||||
|
"technology_domains",
|
||||||
|
"high_priority_review_queue",
|
||||||
|
"professional_agent_roles",
|
||||||
|
"rolling_update_controls",
|
||||||
|
"integration_candidates",
|
||||||
|
"priority_workplan",
|
||||||
|
"blocked_gates",
|
||||||
|
"report_contract"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"schema_version": {
|
||||||
|
"type": "string",
|
||||||
|
"const": "ai_technology_radar_readback_v1"
|
||||||
|
},
|
||||||
|
"generated_at": {
|
||||||
|
"type": "string",
|
||||||
|
"minLength": 1
|
||||||
|
},
|
||||||
|
"source_scope": {
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": true
|
||||||
|
},
|
||||||
|
"summary": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"overall_completion_percent",
|
||||||
|
"ai_technology_radar_completion_percent",
|
||||||
|
"technology_count",
|
||||||
|
"technology_area_count",
|
||||||
|
"source_count",
|
||||||
|
"changed_technologies",
|
||||||
|
"review_queue_count",
|
||||||
|
"source_failures",
|
||||||
|
"high_priority_count",
|
||||||
|
"rolling_update_status"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"overall_completion_percent": {"type": "number"},
|
||||||
|
"ai_technology_radar_completion_percent": {"type": "number"},
|
||||||
|
"technology_count": {"type": "integer", "minimum": 0},
|
||||||
|
"technology_area_count": {"type": "integer", "minimum": 0},
|
||||||
|
"source_count": {"type": "integer", "minimum": 0},
|
||||||
|
"changed_technologies": {"type": "integer", "minimum": 0},
|
||||||
|
"review_queue_count": {"type": "integer", "minimum": 0},
|
||||||
|
"source_failures": {"type": "integer", "minimum": 0},
|
||||||
|
"high_priority_count": {"type": "integer", "minimum": 0},
|
||||||
|
"rolling_update_status": {"type": "string", "minLength": 1}
|
||||||
|
},
|
||||||
|
"additionalProperties": true
|
||||||
|
},
|
||||||
|
"policy": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"read_only",
|
||||||
|
"raw_chat_history_synced",
|
||||||
|
"sdk_installation_approved",
|
||||||
|
"paid_api_calls_approved",
|
||||||
|
"production_routing_approved",
|
||||||
|
"telegram_send_approved",
|
||||||
|
"model_provider_switch_approved",
|
||||||
|
"host_write_approved",
|
||||||
|
"openclaw_replacement_approved"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"read_only": {"type": "boolean", "const": true},
|
||||||
|
"raw_chat_history_synced": {"type": "boolean", "const": false},
|
||||||
|
"sdk_installation_approved": {"type": "boolean", "const": false},
|
||||||
|
"paid_api_calls_approved": {"type": "boolean", "const": false},
|
||||||
|
"production_routing_approved": {"type": "boolean", "const": false},
|
||||||
|
"telegram_send_approved": {"type": "boolean", "const": false},
|
||||||
|
"model_provider_switch_approved": {"type": "boolean", "const": false},
|
||||||
|
"host_write_approved": {"type": "boolean", "const": false},
|
||||||
|
"openclaw_replacement_approved": {"type": "boolean", "const": false}
|
||||||
|
},
|
||||||
|
"additionalProperties": true
|
||||||
|
},
|
||||||
|
"technology_area_counts": {
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": {"type": "integer", "minimum": 0}
|
||||||
|
},
|
||||||
|
"technology_domains": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {"type": "object", "additionalProperties": true}
|
||||||
|
},
|
||||||
|
"high_priority_review_queue": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {"type": "object", "additionalProperties": true}
|
||||||
|
},
|
||||||
|
"professional_agent_roles": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {"type": "object", "additionalProperties": true}
|
||||||
|
},
|
||||||
|
"rolling_update_controls": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {"type": "object", "additionalProperties": true}
|
||||||
|
},
|
||||||
|
"integration_candidates": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {"type": "object", "additionalProperties": true}
|
||||||
|
},
|
||||||
|
"priority_workplan": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {"type": "object", "additionalProperties": true}
|
||||||
|
},
|
||||||
|
"blocked_gates": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {"type": "string", "minLength": 1}
|
||||||
|
},
|
||||||
|
"report_contract": {
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false
|
||||||
|
}
|
||||||
157
docs/schemas/ai_technology_watch_report_v1.schema.json
Normal file
157
docs/schemas/ai_technology_watch_report_v1.schema.json
Normal file
@@ -0,0 +1,157 @@
|
|||||||
|
{
|
||||||
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
|
"$id": "urn:awoooi:ai-technology-watch-report-v1",
|
||||||
|
"title": "AWOOOI AI 技術雷達來源監控報告 (v1)",
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"schema_version",
|
||||||
|
"generated_at",
|
||||||
|
"mode",
|
||||||
|
"registry",
|
||||||
|
"cadence",
|
||||||
|
"policy",
|
||||||
|
"summary",
|
||||||
|
"technology_area_counts",
|
||||||
|
"technologies",
|
||||||
|
"review_queue",
|
||||||
|
"new_technology_discovery",
|
||||||
|
"failures"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"schema_version": {
|
||||||
|
"type": "string",
|
||||||
|
"const": "ai_technology_watch_report_v1"
|
||||||
|
},
|
||||||
|
"generated_at": {
|
||||||
|
"type": "string",
|
||||||
|
"minLength": 1
|
||||||
|
},
|
||||||
|
"mode": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": ["offline", "live"]
|
||||||
|
},
|
||||||
|
"registry": {
|
||||||
|
"type": "object",
|
||||||
|
"required": ["path", "schema_version", "updated_at"],
|
||||||
|
"properties": {
|
||||||
|
"path": {"type": "string"},
|
||||||
|
"schema_version": {"type": "string"},
|
||||||
|
"updated_at": {"type": "string"}
|
||||||
|
},
|
||||||
|
"additionalProperties": true
|
||||||
|
},
|
||||||
|
"cadence": {
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": true
|
||||||
|
},
|
||||||
|
"policy": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"read_only",
|
||||||
|
"sdk_installation_approved",
|
||||||
|
"paid_api_calls_approved",
|
||||||
|
"production_routing_approved",
|
||||||
|
"telegram_send_approved",
|
||||||
|
"model_provider_switch_approved",
|
||||||
|
"host_write_approved"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"read_only": {"type": "boolean", "const": true},
|
||||||
|
"sdk_installation_approved": {"type": "boolean", "const": false},
|
||||||
|
"paid_api_calls_approved": {"type": "boolean", "const": false},
|
||||||
|
"production_routing_approved": {"type": "boolean", "const": false},
|
||||||
|
"telegram_send_approved": {"type": "boolean", "const": false},
|
||||||
|
"model_provider_switch_approved": {"type": "boolean", "const": false},
|
||||||
|
"host_write_approved": {"type": "boolean", "const": false}
|
||||||
|
},
|
||||||
|
"additionalProperties": true
|
||||||
|
},
|
||||||
|
"summary": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"technology_count",
|
||||||
|
"technology_area_count",
|
||||||
|
"source_count",
|
||||||
|
"changed_technologies",
|
||||||
|
"watch_only_technologies",
|
||||||
|
"review_queue_count",
|
||||||
|
"source_failure_count",
|
||||||
|
"high_priority_count"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"technology_count": {"type": "integer", "minimum": 0},
|
||||||
|
"technology_area_count": {"type": "integer", "minimum": 0},
|
||||||
|
"source_count": {"type": "integer", "minimum": 0},
|
||||||
|
"changed_technologies": {"type": "integer", "minimum": 0},
|
||||||
|
"watch_only_technologies": {"type": "integer", "minimum": 0},
|
||||||
|
"review_queue_count": {"type": "integer", "minimum": 0},
|
||||||
|
"source_failure_count": {"type": "integer", "minimum": 0},
|
||||||
|
"high_priority_count": {"type": "integer", "minimum": 0}
|
||||||
|
},
|
||||||
|
"additionalProperties": true
|
||||||
|
},
|
||||||
|
"technology_area_counts": {
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": {"type": "integer", "minimum": 0}
|
||||||
|
},
|
||||||
|
"technologies": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {"$ref": "#/$defs/technology"}
|
||||||
|
},
|
||||||
|
"review_queue": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {"type": "object", "additionalProperties": true}
|
||||||
|
},
|
||||||
|
"new_technology_discovery": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {"type": "object", "additionalProperties": true}
|
||||||
|
},
|
||||||
|
"failures": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {"type": "string"}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"$defs": {
|
||||||
|
"technology": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"technology_id",
|
||||||
|
"display_name",
|
||||||
|
"technology_area",
|
||||||
|
"integration_surface",
|
||||||
|
"awoooi_role",
|
||||||
|
"evaluation_priority",
|
||||||
|
"requires_cost_approval",
|
||||||
|
"requires_dependency_approval",
|
||||||
|
"requires_security_review",
|
||||||
|
"sources",
|
||||||
|
"changed",
|
||||||
|
"decision",
|
||||||
|
"recommended_actions"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"technology_id": {"type": "string", "minLength": 1},
|
||||||
|
"display_name": {"type": "string", "minLength": 1},
|
||||||
|
"technology_area": {"type": "string", "minLength": 1},
|
||||||
|
"integration_surface": {"type": "string"},
|
||||||
|
"awoooi_role": {"type": "string"},
|
||||||
|
"evaluation_priority": {"type": "string"},
|
||||||
|
"requires_cost_approval": {"type": "boolean"},
|
||||||
|
"requires_dependency_approval": {"type": "boolean"},
|
||||||
|
"requires_security_review": {"type": "boolean"},
|
||||||
|
"sources": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {"type": "object", "additionalProperties": true}
|
||||||
|
},
|
||||||
|
"changed": {"type": "boolean"},
|
||||||
|
"decision": {"type": "string"},
|
||||||
|
"recommended_actions": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {"type": "string"}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false
|
||||||
|
}
|
||||||
82
scripts/agents/ai-technology-watch.py
Normal file
82
scripts/agents/ai-technology-watch.py
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Run the AWOOOI read-only AI technology watch."""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import importlib.util
|
||||||
|
import json
|
||||||
|
import sys
|
||||||
|
from pathlib import Path
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
|
|
||||||
|
ROOT = Path(__file__).resolve().parents[2]
|
||||||
|
API_ROOT = ROOT / "apps" / "api"
|
||||||
|
SERVICE_PATH = ROOT / "apps" / "api" / "src" / "services" / "ai_technology_watch.py"
|
||||||
|
run_ai_technology_watch = None
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> int:
|
||||||
|
global run_ai_technology_watch
|
||||||
|
if run_ai_technology_watch is None:
|
||||||
|
run_ai_technology_watch = _load_service()
|
||||||
|
|
||||||
|
parser = argparse.ArgumentParser(description="Run AWOOOI AI technology watch.")
|
||||||
|
parser.add_argument(
|
||||||
|
"--registry",
|
||||||
|
default="docs/ai/ai-technology-watch-sources.v1.json",
|
||||||
|
help="AI technology watch registry JSON",
|
||||||
|
)
|
||||||
|
parser.add_argument("--output", required=True, help="report output JSON")
|
||||||
|
parser.add_argument(
|
||||||
|
"--mode",
|
||||||
|
choices=("offline", "live"),
|
||||||
|
default="live",
|
||||||
|
help="offline validates registry only; live fetches primary sources",
|
||||||
|
)
|
||||||
|
parser.add_argument("--previous-report")
|
||||||
|
parser.add_argument("--timeout-seconds", type=int, default=12)
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
registry = _read_json(Path(args.registry))
|
||||||
|
previous = _read_json(Path(args.previous_report)) if args.previous_report else None
|
||||||
|
report = run_ai_technology_watch(
|
||||||
|
registry,
|
||||||
|
registry_path=args.registry,
|
||||||
|
mode=args.mode,
|
||||||
|
previous_report=previous,
|
||||||
|
timeout_seconds=args.timeout_seconds,
|
||||||
|
)
|
||||||
|
Path(args.output).write_text(
|
||||||
|
json.dumps(report, ensure_ascii=False, indent=2, sort_keys=True) + "\n",
|
||||||
|
encoding="utf-8",
|
||||||
|
)
|
||||||
|
print(json.dumps(report["summary"], ensure_ascii=False, sort_keys=True))
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
def _read_json(path: Path) -> dict[str, Any]:
|
||||||
|
with path.open(encoding="utf-8") as handle:
|
||||||
|
payload = json.load(handle)
|
||||||
|
if not isinstance(payload, dict):
|
||||||
|
raise SystemExit(f"{path}: expected JSON object")
|
||||||
|
return payload
|
||||||
|
|
||||||
|
|
||||||
|
def _load_service() -> Any:
|
||||||
|
api_root = str(API_ROOT)
|
||||||
|
if api_root not in sys.path:
|
||||||
|
sys.path.insert(0, api_root)
|
||||||
|
module_name = "awoooi_ai_technology_watch_service"
|
||||||
|
spec = importlib.util.spec_from_file_location(module_name, SERVICE_PATH)
|
||||||
|
if spec is None or spec.loader is None:
|
||||||
|
raise SystemExit(f"cannot load AI technology watch service from {SERVICE_PATH}")
|
||||||
|
module = importlib.util.module_from_spec(spec)
|
||||||
|
sys.modules[module_name] = module
|
||||||
|
spec.loader.exec_module(module)
|
||||||
|
return module.run_ai_technology_watch
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
raise SystemExit(main())
|
||||||
434
scripts/dev/ai-technology-radar-readback.py
Normal file
434
scripts/dev/ai-technology-radar-readback.py
Normal file
@@ -0,0 +1,434 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Build the AWOOOI AI technology radar readback artifact."""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import json
|
||||||
|
from collections import defaultdict
|
||||||
|
from datetime import datetime, timezone
|
||||||
|
from pathlib import Path
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
|
|
||||||
|
def build_radar(
|
||||||
|
*,
|
||||||
|
technology_watch: dict[str, Any],
|
||||||
|
agent_market_radar: dict[str, Any],
|
||||||
|
evidence_commit: str,
|
||||||
|
generated_at: str | None = None,
|
||||||
|
) -> dict[str, Any]:
|
||||||
|
"""Build a read-only AI technology radar readback from committed evidence."""
|
||||||
|
_require_schema(technology_watch, "ai_technology_watch_report_v1", "technology_watch")
|
||||||
|
_require_schema(agent_market_radar, "ai_agent_market_radar_readback_v1", "agent_market_radar")
|
||||||
|
|
||||||
|
watch_summary = technology_watch.get("summary") or {}
|
||||||
|
agent_summary = agent_market_radar.get("summary") or {}
|
||||||
|
source_count = int(watch_summary.get("source_count", 0))
|
||||||
|
failure_count = int(watch_summary.get("source_failure_count", 0))
|
||||||
|
success_rate = _success_rate(source_count, failure_count)
|
||||||
|
|
||||||
|
return {
|
||||||
|
"schema_version": "ai_technology_radar_readback_v1",
|
||||||
|
"generated_at": generated_at or datetime.now(timezone.utc).isoformat(),
|
||||||
|
"source_scope": {
|
||||||
|
"technology_watch_report": "docs/evaluations/ai_technology_watch_report_2026-06-25.json",
|
||||||
|
"technology_source_registry": "docs/ai/ai-technology-watch-sources.v1.json",
|
||||||
|
"agent_market_radar_readback": "docs/operations/ai-agent-market-radar-readback.snapshot.json",
|
||||||
|
"gitea_main_evidence_basis_commit": evidence_commit,
|
||||||
|
"scope_note": "本讀回只整合已提交的只讀來源監控、AI Agent 市場雷達與治理 gate;不包含 raw chat history、secret、session 或本機工作視窗內容。",
|
||||||
|
},
|
||||||
|
"summary": {
|
||||||
|
"overall_completion_percent": float(agent_summary.get("overall_completion_percent", 42.2)),
|
||||||
|
"ai_technology_radar_completion_percent": success_rate,
|
||||||
|
"technology_count": int(watch_summary.get("technology_count", 0)),
|
||||||
|
"technology_area_count": int(watch_summary.get("technology_area_count", 0)),
|
||||||
|
"source_count": source_count,
|
||||||
|
"changed_technologies": int(watch_summary.get("changed_technologies", 0)),
|
||||||
|
"review_queue_count": int(watch_summary.get("review_queue_count", 0)),
|
||||||
|
"source_failures": failure_count,
|
||||||
|
"high_priority_count": int(watch_summary.get("high_priority_count", 0)),
|
||||||
|
"rolling_update_status": "near_real_time_watch_ready_integration_gated",
|
||||||
|
},
|
||||||
|
"policy": {
|
||||||
|
"read_only": True,
|
||||||
|
"raw_chat_history_synced": False,
|
||||||
|
"sdk_installation_approved": False,
|
||||||
|
"paid_api_calls_approved": False,
|
||||||
|
"production_routing_approved": False,
|
||||||
|
"telegram_send_approved": False,
|
||||||
|
"model_provider_switch_approved": False,
|
||||||
|
"host_write_approved": False,
|
||||||
|
"openclaw_replacement_approved": False,
|
||||||
|
},
|
||||||
|
"technology_area_counts": dict(technology_watch.get("technology_area_counts") or {}),
|
||||||
|
"technology_domains": _technology_domains(technology_watch),
|
||||||
|
"high_priority_review_queue": _high_priority_review_queue(technology_watch),
|
||||||
|
"professional_agent_roles": _professional_agent_roles(),
|
||||||
|
"rolling_update_controls": _rolling_update_controls(technology_watch),
|
||||||
|
"integration_candidates": _integration_candidates(technology_watch),
|
||||||
|
"priority_workplan": _priority_workplan(),
|
||||||
|
"blocked_gates": [
|
||||||
|
"sdk_installation_approved=false",
|
||||||
|
"paid_api_calls_approved=false",
|
||||||
|
"production_routing_approved=false",
|
||||||
|
"telegram_send_approved=false",
|
||||||
|
"model_provider_switch_approved=false",
|
||||||
|
"host_write_approved=false",
|
||||||
|
"openclaw_replacement_approved=false",
|
||||||
|
"replay_shadow_canary_gate_required=true",
|
||||||
|
"cost_and_data_boundary_review_required=true",
|
||||||
|
],
|
||||||
|
"report_contract": {
|
||||||
|
"api_endpoint": "/api/v1/agents/ai-technology-radar-readback",
|
||||||
|
"frontend_target": "/zh-TW/governance?tab=agent-market",
|
||||||
|
"schedule_workflow": ".gitea/workflows/ai-technology-watch.yaml",
|
||||||
|
"schedule_enabled": True,
|
||||||
|
"schedule_cron_utc": "0 */6 * * *",
|
||||||
|
"near_real_time": "每 6 小時讀取 primary sources,偵測主流 AI 技術版本、文件與 release 變更。",
|
||||||
|
"daily": "每日彙整變更、來源失敗、審核佇列與可自動處理項目。",
|
||||||
|
"weekly": "每週做技術 scorecard,決定 sandbox / replay / adapter design 優先級。",
|
||||||
|
"monthly": "每月進行策略 review,決定納入 roadmap、維持 watch-only 或移出監控。",
|
||||||
|
"human_review_required_for": [
|
||||||
|
"新 SDK / package / MCP server 安裝",
|
||||||
|
"付費 API 或 token 上限變更",
|
||||||
|
"模型 provider / 生產路由切換",
|
||||||
|
"Telegram Bot 即時發送或審批按鈕策略變更",
|
||||||
|
"主機、K8s、workflow、Nginx、secret 或資料層寫入",
|
||||||
|
"OpenClaw 生產決策核心替換、拆分或降級",
|
||||||
|
],
|
||||||
|
"agent_auto_allowed_for": [
|
||||||
|
"官方來源只讀監控",
|
||||||
|
"版本與文件 hash 比對",
|
||||||
|
"審核佇列分類",
|
||||||
|
"繁中 no-send 報告草稿",
|
||||||
|
"離線 replay fixture 準備",
|
||||||
|
"低風險文件與讀回 snapshot 更新提案",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def render_markdown(payload: dict[str, Any]) -> str:
|
||||||
|
"""Render a Traditional Chinese operator report."""
|
||||||
|
summary = payload["summary"]
|
||||||
|
lines = [
|
||||||
|
"# AI 技術雷達與滾動更新讀回",
|
||||||
|
"",
|
||||||
|
f"- 產生時間:`{payload['generated_at']}`",
|
||||||
|
f"- 整體治理完成度:`{summary['overall_completion_percent']}%`",
|
||||||
|
f"- AI 技術雷達來源成功率:`{summary['ai_technology_radar_completion_percent']}%`",
|
||||||
|
f"- 監控技術項目:`{summary['technology_count']}`",
|
||||||
|
f"- 技術領域:`{summary['technology_area_count']}`",
|
||||||
|
f"- 官方 / primary sources:`{summary['source_count']}`",
|
||||||
|
f"- 來源失敗:`{summary['source_failures']}`",
|
||||||
|
f"- 需要審核變更:`{summary['changed_technologies']}`",
|
||||||
|
f"- 高優先級項目:`{summary['high_priority_count']}`",
|
||||||
|
f"- 滾動更新狀態:`{summary['rolling_update_status']}`",
|
||||||
|
"",
|
||||||
|
"## 技術領域覆蓋",
|
||||||
|
"",
|
||||||
|
"| 技術領域 | 技術數 | 高優先級 | 需要審核 | 代表技術 |",
|
||||||
|
"|---|---:|---:|---:|---|",
|
||||||
|
]
|
||||||
|
for domain in payload["technology_domains"]:
|
||||||
|
lines.append(
|
||||||
|
f"| `{domain['technology_area']}` | `{domain['technology_count']}` | "
|
||||||
|
f"`{domain['high_priority_count']}` | `{domain['changed_count']}` | "
|
||||||
|
f"{', '.join(domain['representative_technologies'])} |"
|
||||||
|
)
|
||||||
|
|
||||||
|
lines.extend([
|
||||||
|
"",
|
||||||
|
"## 高優先級審核佇列",
|
||||||
|
"",
|
||||||
|
"| 技術 | 領域 | 優先級 | Gate | 下一步 |",
|
||||||
|
"|---|---|---|---|---|",
|
||||||
|
])
|
||||||
|
for item in payload["high_priority_review_queue"]:
|
||||||
|
lines.append(
|
||||||
|
f"| {item['display_name']} | `{item['technology_area']}` | "
|
||||||
|
f"`{item['evaluation_priority']}` | `{item['gate_status']}` | {item['next_gate']} |"
|
||||||
|
)
|
||||||
|
|
||||||
|
lines.extend([
|
||||||
|
"",
|
||||||
|
"## Agent 專業分工",
|
||||||
|
"",
|
||||||
|
"| Agent | 專業角色 | 自動化範圍 | 需要審核的邊界 |",
|
||||||
|
"|---|---|---|---|",
|
||||||
|
])
|
||||||
|
for role in payload["professional_agent_roles"]:
|
||||||
|
lines.append(
|
||||||
|
f"| {role['agent']} | {role['professional_role']} | "
|
||||||
|
f"{role['auto_scope']} | {role['review_boundary']} |"
|
||||||
|
)
|
||||||
|
|
||||||
|
lines.extend([
|
||||||
|
"",
|
||||||
|
"## 滾動更新控制",
|
||||||
|
"",
|
||||||
|
"| 節奏 | Agent 可自動做什麼 | 輸出 | Gate |",
|
||||||
|
"|---|---|---|---|",
|
||||||
|
])
|
||||||
|
for control in payload["rolling_update_controls"]:
|
||||||
|
lines.append(
|
||||||
|
f"| {control['cadence']} | {control['agent_auto_action']} | "
|
||||||
|
f"{control['output']} | `{control['gate']}` |"
|
||||||
|
)
|
||||||
|
|
||||||
|
lines.extend([
|
||||||
|
"",
|
||||||
|
"## 優先工作清單",
|
||||||
|
"",
|
||||||
|
"| 順序 | 工作 | 優先級 | 自動化模式 | 完成定義 |",
|
||||||
|
"|---:|---|---|---|---|",
|
||||||
|
])
|
||||||
|
for item in payload["priority_workplan"]:
|
||||||
|
lines.append(
|
||||||
|
f"| {item['order']} | {item['work_item']} | `{item['priority']}` | "
|
||||||
|
f"`{item['automation_mode']}` | {item['done_definition']} |"
|
||||||
|
)
|
||||||
|
|
||||||
|
lines.extend([
|
||||||
|
"",
|
||||||
|
"## 仍被 Gate 擋下",
|
||||||
|
"",
|
||||||
|
])
|
||||||
|
for gate in payload["blocked_gates"]:
|
||||||
|
lines.append(f"- `{gate}`")
|
||||||
|
lines.append("")
|
||||||
|
return "\n".join(lines)
|
||||||
|
|
||||||
|
|
||||||
|
def _require_schema(payload: dict[str, Any], schema_version: str, label: str) -> None:
|
||||||
|
if payload.get("schema_version") != schema_version:
|
||||||
|
raise ValueError(f"{label}: expected {schema_version}")
|
||||||
|
|
||||||
|
|
||||||
|
def _success_rate(source_count: int, failure_count: int) -> float:
|
||||||
|
if source_count <= 0:
|
||||||
|
return 0.0
|
||||||
|
return round(((source_count - failure_count) / source_count) * 100, 1)
|
||||||
|
|
||||||
|
|
||||||
|
def _technology_domains(report: dict[str, Any]) -> list[dict[str, Any]]:
|
||||||
|
grouped: dict[str, list[dict[str, Any]]] = defaultdict(list)
|
||||||
|
for row in report.get("technologies") or []:
|
||||||
|
grouped[str(row.get("technology_area") or "uncategorized")].append(row)
|
||||||
|
|
||||||
|
domains = []
|
||||||
|
for area, rows in sorted(grouped.items()):
|
||||||
|
high_priority = [row for row in rows if row.get("evaluation_priority") in {"p0", "p1"}]
|
||||||
|
changed = [row for row in rows if row.get("changed")]
|
||||||
|
domains.append({
|
||||||
|
"technology_area": area,
|
||||||
|
"technology_count": len(rows),
|
||||||
|
"high_priority_count": len(high_priority),
|
||||||
|
"changed_count": len(changed),
|
||||||
|
"representative_technologies": [
|
||||||
|
str(row.get("display_name") or row.get("technology_id"))
|
||||||
|
for row in rows[:4]
|
||||||
|
],
|
||||||
|
})
|
||||||
|
return domains
|
||||||
|
|
||||||
|
|
||||||
|
def _high_priority_review_queue(report: dict[str, Any]) -> list[dict[str, Any]]:
|
||||||
|
rows = [
|
||||||
|
row
|
||||||
|
for row in report.get("technologies") or []
|
||||||
|
if row.get("evaluation_priority") in {"p0", "p1"} and row.get("changed")
|
||||||
|
]
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
"technology_id": row.get("technology_id"),
|
||||||
|
"display_name": row.get("display_name"),
|
||||||
|
"technology_area": row.get("technology_area"),
|
||||||
|
"evaluation_priority": row.get("evaluation_priority"),
|
||||||
|
"gate_status": "scorecard_required_before_integration",
|
||||||
|
"next_gate": "刷新 scorecard,若涉及 SDK/API/route/Telegram/host write 則送人工審核。",
|
||||||
|
"requires_cost_approval": bool(row.get("requires_cost_approval")),
|
||||||
|
"requires_dependency_approval": bool(row.get("requires_dependency_approval")),
|
||||||
|
"requires_security_review": bool(row.get("requires_security_review")),
|
||||||
|
}
|
||||||
|
for row in rows[:12]
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def _professional_agent_roles() -> list[dict[str, Any]]:
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
"agent": "OpenClaw",
|
||||||
|
"professional_role": "生產決策仲裁者、風險分級與最後 policy guard",
|
||||||
|
"auto_scope": "維持現有 production baseline、讀取 replay / shadow 評分、拒絕無證據替換",
|
||||||
|
"review_boundary": "任何取代、降級、生產路由切換都必須通過 replay / shadow / canary 與人工批准。",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"agent": "NemoTron",
|
||||||
|
"professional_role": "離線回放評估者、模型能力比較、合約輸出 smoke gate",
|
||||||
|
"auto_scope": "只讀 request pack、比對候選輸出、產生 replay scorecard 草稿",
|
||||||
|
"review_boundary": "不得自行呼叫外部 NIM/API、不得讀 labels 作答、不得進生產路由。",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"agent": "Hermes",
|
||||||
|
"professional_role": "知識管理、RAG 整理、報告草稿與長期技能庫維護",
|
||||||
|
"auto_scope": "整理 primary source 摘要、建立 no-send 日週月報、準備人審包",
|
||||||
|
"review_boundary": "不得同步 raw chat history、不得保存 secret、不得直接發 Telegram live report。",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"agent": "MarketRadar",
|
||||||
|
"professional_role": "AI 技術市場雷達、版本監控、來源失敗偵測",
|
||||||
|
"auto_scope": "每 6 小時只讀 primary sources、產生 freshness / review queue",
|
||||||
|
"review_boundary": "不得自動新增 SDK、不得自動修改 provider route 或 workflow 行為。",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"agent": "Critic / Reviewer",
|
||||||
|
"professional_role": "獨立審核、反例檢查、整合風險評分",
|
||||||
|
"auto_scope": "檢查政策旗標、來源可靠性、成本與資安風險",
|
||||||
|
"review_boundary": "只能輸出 blocked / candidate / owner_review,不得直接執行寫入。",
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def _rolling_update_controls(report: dict[str, Any]) -> list[dict[str, Any]]:
|
||||||
|
cadence = report.get("cadence") or {}
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
"cadence": "每 6 小時",
|
||||||
|
"agent_auto_action": "讀取官方文件、PyPI、npm、GitHub release、primary source hash。",
|
||||||
|
"output": "AI 技術 watch report、來源失敗清單、review queue。",
|
||||||
|
"gate": "read_only_only",
|
||||||
|
"cadence_source": cadence.get("near_real_time_watch", ""),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cadence": "每日",
|
||||||
|
"agent_auto_action": "依 business applicability、成本、依賴、資安、AWOOOI fit 分類。",
|
||||||
|
"output": "日報摘要與中低風險自動處理建議。",
|
||||||
|
"gate": "no_send_report_until_delivery_gate",
|
||||||
|
"cadence_source": cadence.get("daily_triage", ""),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cadence": "每週",
|
||||||
|
"agent_auto_action": "刷新 scorecard,決定 sandbox / replay / adapter design 優先級。",
|
||||||
|
"output": "週報、優先序、候選整合審查包。",
|
||||||
|
"gate": "scorecard_required_before_replay",
|
||||||
|
"cadence_source": cadence.get("weekly_scorecard", ""),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cadence": "每月",
|
||||||
|
"agent_auto_action": "彙整趨勢,提出 roadmap / watch-only / retire 建議。",
|
||||||
|
"output": "月報與策略審核包。",
|
||||||
|
"gate": "human_review_for_strategy_or_production_change",
|
||||||
|
"cadence_source": cadence.get("monthly_strategy_review", ""),
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def _integration_candidates(report: dict[str, Any]) -> list[dict[str, Any]]:
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
"technology_id": row.get("technology_id"),
|
||||||
|
"display_name": row.get("display_name"),
|
||||||
|
"technology_area": row.get("technology_area"),
|
||||||
|
"integration_surface": row.get("integration_surface"),
|
||||||
|
"awoooi_role": row.get("awoooi_role"),
|
||||||
|
"changed": bool(row.get("changed")),
|
||||||
|
"decision": row.get("decision"),
|
||||||
|
"recommended_actions": row.get("recommended_actions") or [],
|
||||||
|
}
|
||||||
|
for row in report.get("technologies") or []
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def _priority_workplan() -> list[dict[str, Any]]:
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
"order": 1,
|
||||||
|
"priority": "P0",
|
||||||
|
"work_item": "AI 技術雷達 primary source 監控產品化",
|
||||||
|
"automation_mode": "agent_auto_read_only",
|
||||||
|
"done_definition": "API、snapshot、Markdown、schema、測試與 production readback 都能顯示技術領域、來源與 Gate。",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"order": 2,
|
||||||
|
"priority": "P0",
|
||||||
|
"work_item": "近即時版本 / release / docs 變更偵測",
|
||||||
|
"automation_mode": "agent_auto_schedule_read_only",
|
||||||
|
"done_definition": "每 6 小時可跑 watch;失敗來源會進日報,不會自動整合。",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"order": 3,
|
||||||
|
"priority": "P0",
|
||||||
|
"work_item": "OpenClaw / Hermes / NemoTron / MarketRadar 專業分工與成長紀錄",
|
||||||
|
"automation_mode": "agent_auto_read_model_human_review_for_write",
|
||||||
|
"done_definition": "每個 Agent 的角色、輸出、學習寫回與限制都能被前端讀回。",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"order": 4,
|
||||||
|
"priority": "P1",
|
||||||
|
"work_item": "AI 技術 scorecard 與 sandbox / replay 優先級",
|
||||||
|
"automation_mode": "agent_propose_owner_review",
|
||||||
|
"done_definition": "高優先級變更先進 scorecard,再進 no-cost/no-write sandbox 或 replay 計畫。",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"order": 5,
|
||||||
|
"priority": "P1",
|
||||||
|
"work_item": "Telegram Bot 報告與高風險審核橋接",
|
||||||
|
"automation_mode": "blocked_until_telegram_send_gate",
|
||||||
|
"done_definition": "低中風險只告警回報;高風險需 owner approval 後才可發送或執行。",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"order": 6,
|
||||||
|
"priority": "P2",
|
||||||
|
"work_item": "新 AI 技術探索與 watchlist 擴充",
|
||||||
|
"automation_mode": "agent_auto_discover_human_classify",
|
||||||
|
"done_definition": "GitHub topic / package registry / 官方 blog 可提出候選,但加入正式 watchlist 前需審核。",
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def load_json(path: Path) -> dict[str, Any]:
|
||||||
|
with path.open(encoding="utf-8") as handle:
|
||||||
|
payload = json.load(handle)
|
||||||
|
if not isinstance(payload, dict):
|
||||||
|
raise ValueError(f"{path}: expected JSON object")
|
||||||
|
return payload
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> int:
|
||||||
|
parser = argparse.ArgumentParser(description="Build AI technology radar readback.")
|
||||||
|
parser.add_argument("--technology-watch", required=True)
|
||||||
|
parser.add_argument("--agent-market-radar", required=True)
|
||||||
|
parser.add_argument("--evidence-commit", required=True)
|
||||||
|
parser.add_argument("--output", required=True)
|
||||||
|
parser.add_argument("--markdown-output", required=True)
|
||||||
|
parser.add_argument("--markdown-alias-output")
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
payload = build_radar(
|
||||||
|
technology_watch=load_json(Path(args.technology_watch)),
|
||||||
|
agent_market_radar=load_json(Path(args.agent_market_radar)),
|
||||||
|
evidence_commit=args.evidence_commit,
|
||||||
|
)
|
||||||
|
Path(args.output).write_text(
|
||||||
|
json.dumps(payload, ensure_ascii=False, indent=2, sort_keys=True) + "\n",
|
||||||
|
encoding="utf-8",
|
||||||
|
)
|
||||||
|
markdown = render_markdown(payload)
|
||||||
|
Path(args.markdown_output).write_text(markdown, encoding="utf-8")
|
||||||
|
if args.markdown_alias_output:
|
||||||
|
Path(args.markdown_alias_output).write_text(markdown, encoding="utf-8")
|
||||||
|
print(
|
||||||
|
"AI_TECHNOLOGY_RADAR_READBACK_OK "
|
||||||
|
f"overall={payload['summary']['overall_completion_percent']}% "
|
||||||
|
f"technology={payload['summary']['technology_count']} "
|
||||||
|
f"sources={payload['summary']['source_count']} "
|
||||||
|
f"changed={payload['summary']['changed_technologies']} "
|
||||||
|
f"failures={payload['summary']['source_failures']}"
|
||||||
|
)
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
raise SystemExit(main())
|
||||||
Reference in New Issue
Block a user